JZOJ-senior-5952. 【NOIP2018模拟11.5A组】凯旋而归

版权声明:本文为博主原创文章,未经博主允许不得转载。 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

记前缀异或和为 b i b_i ,则要求 b j + ( b i x o r b j ) b_j+(b_i xor b_j) ( j &lt; = i j&lt;=i ) 的最大值
b i b_i 拆位进行考虑
假如 b i b_i 某一位为1,那么无论 b j b_j 这一位是 0 0 还是 1 1 ,进行上述式子以后均为 1 1
所以 b j b_j 对这一位不会有任何贡献,所以我们只关心 b i b_i 二进制下为 0 0 的位
不难发现,在 k k 位取 1 1 会比在 k k 位小的位全取 1 1
所以我们采取贪心的策略,只要前面可以取 1 1 就取,从高位往低位贪心
f i f_i 表示满足 i i a n d and b j b_j = i =i 的最小的 j j ,即 b j b_j 的子集有 i i
记当前找到的可以填充进去的数为 n o w now
我们想把第 k k 位的贡献从 0 2 k 1 0*2^{k-1} 变成 2 2 k 1 2*2^{k-1}
只需要判断 f n o w 2 k 1 f_{now|2^{k-1}} 是否小于等于 i i
若是,则 n o w = 2 k 1 now|=2^{k-1} ,贡献便多了 2 2 k 1 2*2^{k-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);
	}
}

猜你喜欢

转载自blog.csdn.net/HuangXinyue1017/article/details/83892339