Description
Input
Output
Sample Input
5 and 1 3 5 2 7 1
Sample Output
1 1 2 1 5 1 1 3
Data Constraint
Solution
- 一道看起来很神仙的题目,实际上运用了平衡规划的神奇技巧。
- 让我们先来看一看暴力。
- 我们设 fi 表示 a=i 时的答案。
- 每一次加入一个数都可以跟任意一个i进行运算更新fi
-
这样我们能做到 O(216) 修改, O(1) 查询。
- 接下来我们引入平衡规划的思想。对于每加入一个数,我们都要分别对其做以上的操作,我们能不能平衡一下,变成 O(28) 修改, O(28) 查询呢?
- 实际上这就是这题的突破口。
- 又因为这是二进制运算,我们不难想到将其拆成两半,一半长度是28,将待查询的数称作A,以加入的数称作B,设 f[s1][s2] 表示A的前半段为s1,B的后半段为s2,A与B前半段运算的最大值。
- 这个状态十分神奇。
- 因为我们可以发现,查询的时候只需要枚举B的后半段,s1 确定,用最大值 f[s1][s2] ,和A的后半段与B的后半段运算的结果相加即可得到答案。 O(28) 枚举。
- 而更新f的时候,s2 确定,枚举s1 更新即可, O(28) 。
- 所以我们就可做到 O(n*28) 的时间复杂度。
- 这是我除了分块以外的第一道平衡规划的题目,十分神奇,这类的题目比较少见,还需要好好掌握。
Code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define I int
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof a)
#define N 100004
using namespace std;
I n,opt,tp,now,x,y,mx,tot,f[260][260],g[260][260],S=255;
char c;
void R(I &x){
x=0;char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
}
I w(I x,I y){
if(opt==1) return x&y;
else if(opt==2) return x|y;
return x^y;
}
I main(){
freopen("binary.in","r",stdin);
freopen("binary.out","w",stdout);
R(n);
c=getchar();
while(c<'a'||c>'z') c=getchar();
opt=(c=='a')?1:(c=='o'?2:3);
R(tp);
F(i,0,S){
F(j,0,S) f[i][j]=-0x7fffffff;
}
F(k,1,n){
R(x);
y=x&S;x>>=8;
mx=-1;
F(i,0,S){
now=f[x][i]+w(i,y);
if(now>mx){mx=now;tot=0;}
if(now==mx) tot+=g[x][i];
}
F(i,0,S){
now=w(i,x)<<8;
if(f[i][y]<now) f[i][y]=now,g[i][y]=0;
if(f[i][y]==now) g[i][y]++;
}
if(k>1){
printf("%d",mx);
if(tp) printf(" %d",tot);
printf("\n");
}
}
return 0;
}