版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HuangXinyue1017/article/details/83892339
Time Limits: 1000 ms Memory Limits: 524288 KB
Description
Input
第一行一个整数 n,表示数的个数。
第二行n个整数,第i个整数为ai 。
Output
n行一个整数表示答案,第i行表示序列第i个前缀的帅气值。
Sample Input
5
1 2 3 4 5
Sample Output
1
3
6
10
9
Data Constraint
对于50%的数据,N<=6666
对于100%的数据, N<=456789,0<=ai<=10^6
Solution
记前缀异或和为
,则要求
(
) 的最大值
对
拆位进行考虑
假如
某一位为1,那么无论
这一位是
还是
,进行上述式子以后均为
所以
对这一位不会有任何贡献,所以我们只关心
二进制下为
的位
不难发现,在
位取
会比在
位小的位全取
优
所以我们采取贪心的策略,只要前面可以取
就取,从高位往低位贪心
记
表示满足
的最小的
,即
的子集有
记当前找到的可以填充进去的数为
我们想把第
位的贡献从
变成
只需要判断
是否小于等于
若是,则
,贡献便多了
,否则不做修改
Code
#include<algorithm>
#include<cstring>
#include<cstdio>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int N=456790,MX=1048576;
int n,x,_2[21],b[N],f[MX];
bool bz[MX];
void dfs(int s)
{
if(bz[s]) return; bz[s]=1;
fo(i,0,19) if((_2[i]&s)==0)
dfs(s|_2[i]),f[s]=min(f[s],f[s|_2[i]]);
}
int main()
{
freopen("ak.in","r",stdin);
freopen("ak.out","w",stdout);
scanf("%d",&n);
_2[0]=1;
fo(i,1,19) _2[i]=_2[i-1]<<1;
memset(f,127,sizeof(f));
fo(i,1,n)
{
scanf("%d",&x);
b[i]=b[i-1]^x;
f[b[i]]=min(f[b[i]],i);
}
dfs(0);
fo(i,1,n)
{
int now=0;
fd(j,19,0) if(((b[i]&_2[j])==0)&&(f[now|_2[j]])<i) now|=_2[j];
int ans=b[i]+(now<<1);
printf("%d\n",ans);
}
}