简单的贪心,就直接上代码了:
#include
#include
#include
#include
using namespace std;
#define maxn 110
int T,n,a[maxn],b[maxn];
int main()
{
scanf("%d",&T);while(T--)
{
scanf("%d",&n);
memset(b,0,sizeof(b));
for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[a[i]]++;
int ans=0,now=0;
while(b[now]>1)ans+=2,now++;
while(b[now]>0)ans++,now++;
printf("%d\n",ans);
}
}
令 m i [ i ] , m a [ i ] mi[i],ma[i] mi[i],ma[i] 表示枚举到当前位置,用 i i i 个数能够乘出的最小和最大数,他们的转移只和 m i [ i − 1 ] , m a [ i − 1 ] mi[i-1],ma[i-1] mi[i−1],ma[i−1] 相关,瞎搞搞就好了。
代码如下:
#include
#include
#include
#include
using namespace std;
#define maxn 200010
#define ll long long
int T,n;
ll a[maxn],mi[10],ma[10];
int main()
{
scanf("%d",&T);while(T--)
{
scanf("%d",&n);ll ans=-1e18;
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<=5;i++)mi[i]=1e18,ma[i]=-1e18;
for(int i=1;i<=n;i++){
for(int j=5;j>=2;j--)if(i>=j){
mi[j]=min(mi[j],min(mi[j-1]*a[i],ma[j-1]*a[i]));
ma[j]=max(ma[j],max(mi[j-1]*a[i],ma[j-1]*a[i]));
}
mi[1]=min(mi[1],a[i]);
ma[1]=max(ma[1],a[i]);
ans=max(ans,ma[5]);
}
printf("%lld\n",ans);
}
}
看一下一开始几个重心,如果有两个,那么把其中一个重心的一个叶子给另一个重心,这样重心就唯一了。
代码如下:
#include
#include
#include
#include
using namespace std;
#define maxn 200010
#define pb push_back
int T,n;
vector<int>e[maxn];
int size[maxn],mson[maxn],rt,rt_;
void dfs(int x,int fa){
size[x]=1;mson[x]=0;
for(int y:e[x])if(y!=fa){
dfs(y,x);size[x]+=size[y];
if(size[y]>mson[x])mson[x]=size[y];
}
if(n-size[x]>mson[x])mson[x]=n-size[x];
if(mson[x]<mson[rt])rt=x,rt_=0;
else if(mson[x]==mson[rt])rt_=x;
}
void dfs1(int x,int fa,int &l,int &f){
int son=e[x].size()-1;
if(!son)l=x,f=fa;
else if(e[x][0]!=fa)dfs1(e[x][0],x,l,f);
else dfs1(e[x][1],x,l,f);
}
int main()
{
scanf("%d",&T);while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)e[i].clear();
for(int i=1,x,y;i<n;i++)scanf("%d %d",&x,&y),e[x].pb(y),e[y].pb(x);
mson[rt=rt_=0]=1e9;dfs(1,0);
if(rt_){
int l,f;
dfs1(rt,rt_,l,f);
printf("%d %d\n%d %d\n",l,f,l,rt_);
}else{
printf("%d %d\n%d %d\n",1,e[1][0],1,e[1][0]);
}
}
}
先考虑如何将一个序列拆成一个不下降和一个不上升的序列。考虑只做减法,让这个序列变成不上升序列,那么就是要将每一个极长不下降子段整体减小,直到最大值等于上一个子段的最小值。
那么每个位置减去的值,一定能够形成一个不下降子序列,两个序列就构造完了。然后还要使他们的最大值最小,令 a , b a,b a,b 为两个序列当前的最大值,显然可以让大的那个整体减小,小的整体增加,使得最大值为 ⌈ a + b 2 ⌉ \lceil \frac {a+b} 2\rceil ⌈2a+b⌉。
不上升子序列的最大值显然就是第一位上的数,而不下降子序列最大值是该序列最后一位上的数,令原序列做差分得到 b b b 数组,那么最后一位上的数就是所有满足 b [ i ] > 0 b[i]>0 b[i]>0 的 b [ i ] b[i] b[i] 之和。
修改的话直接修改差分数组,可以 O ( 1 ) O(1) O(1) 完成。
代码如下:
#include
#include
#include
#include
using namespace std;
#define maxn 100010
#define ll long long
int n,m;
ll a[maxn],b[maxn],sum=0;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]),b[i]=a[i]-a[i-1];
for(int i=2;i<=n;i++)if(b[i]>0)sum+=b[i];
printf("%lld\n",(ll)ceil(1.0*(b[1]+sum)/2.0));
scanf("%d",&m);
for(int i=1,l,r,x;i<=m;i++){
scanf("%d %d %d",&l,&r,&x);
if(l>1&&b[l]>0)sum-=b[l];
b[l]+=x;
if(l>1&&b[l]>0)sum+=b[l];
if(r<n){
r++;
if(b[r]>0)sum-=b[r];
b[r]-=x;
if(b[r]>0)sum+=b[r];
}
printf("%lld\n",(ll)ceil(1.0*(b[1]+sum)/2.0));
}
}
发现 1 0 5 10^5 105 以内的质数有 9592 9592 9592 个,这意味着每个质数大约只能操作 1 1 1 次。
先枚举 n \sqrt n n 以内的质数,将 x x x 质因数分解后这些质数的出现次数可能超过 1 1 1,每次暴力 B B B 一下枚举到的 p p p,然后枚举 p , p 2 , p 3 , . . . p,p^2,p^3,... p,p2,p3,... 依次做 A A A 操作,这样可以确定他们的出现次数。
再考虑大于 n \sqrt n n 的质数,这些质数最多出现一次,并且此时在 n \sqrt n n ~ n n n 范围内已经没有合数了(除了 x x x)。
先考虑 x x x 是大于 n \sqrt n n 的质数,每次 B B B 一半的数,如果 B B B 完之后询问 A 1 A~1 A 1 和预期的不一样,那么这之中一定有 x x x,每个 A A A 一下就能找到,否则就在另外一半里面,重复上面的操作,可以发现这样操作需要的次数大概就是质数个数
次的。
再考虑 x x x 拥有大于 n \sqrt n n 的质数作为因子,但不是质数的情况,那么在上面 B B B 的过程中,看看是否某一次 B B B 出了 2 2 2 就好了。
代码如下:
#include
#include
#include
#include
using namespace std;
#define maxn 100010
int n,ans=1;
int prime[maxn],t=0;
bool v[maxn];
void work(){
for(int i=2;i<=n;i++){
if(!v[i])prime[++t]=i;
for(int j=1;j<=t&&i*prime[j]<=n;j++){
v[i*prime[j]]=true;
if(i%prime[j]==0)break;
}
}
}
int ask(char x,int y){
printf("%c %d\n",x,y);fflush(stdout);
if(x!='C'){
int re;scanf("%d",&re);return re;}
else exit(0);
}
int st=1,sum;
void solve(int l,int r){
int mid=l+r>>1;
for(int i=l;i<=mid;i++){
if(ask('B',prime[i])>1)ask('C',ans*prime[i]);
sum--;
}
if(ask('A',1)!=sum){
for(int i=l;i<=mid;i++)
if(ask('A',prime[i]))ask('C',ans*prime[i]);
}
if(mid<r)solve(mid+1,r);
}
int main()
{
scanf("%d",&n);work();sum=n;
for(;st<=t&&prime[st]*prime[st]<=n;st++){
int &x=prime[st];
sum-=ask('B',x);
if(ask('A',1)!=sum){
sum++;
for(int j=x;j<=n&&ask('A',j);j*=x)ans*=x;
}
}
if(st<=t)solve(st,t);
ask('C',ans);
}