[bzoj5092][乱搞]分割序列

Description

对于一个长度为n的非负整数序列b_1,b_2,…,b_n,定义这个序列的能量为:f(b)=max{i=0,1,…,n}((b_1
xor b
2 xor…xor b_i)+(b{i+1} xor b_{i+2} xor…xor b_n))其中xor表示按位异或(XOR),给定一个长度为n的非 负整数序列a_1,a_2,…,a_n,请计算a的每个前缀的能量值。

Input

第一行包含一个正整数n(n<=300000),表示序列a的长度。
第二行包含n个非负整数a_1,a_2,…,a_n(0<=a_i<=10^6),依次表示a中每个元素的值。

Output

包含n行,每行一个整数,即a每个前缀的能量值。

Sample Input

5

1 2 3 4 5

Sample Output

1

3

6

10

9

题解

感觉这个套路以前没有玩过啊…
求出前缀异或和,然后就是要计算一个 m a x ( s [ j ] + s [ j ] ∧ s [ i ] ) max(s[j]+s[j]\land s[i]) max(s[j]+s[j]s[i])
不考虑别的,我们还是套路地从高位往低位考虑 s [ j ] s[j] s[j]
对于第i位是1的,显然s[j]的第i位是0是1都只会有 2 i 2^i 2i的贡献
对于是0的,我们当然希望s[j]的第i位是1来获得 2 i + 1 2^{i+1} 2i+1的贡献
如果朴素Tire的话我们需要在是1的地方往0和1的孩子搜,0就贪心往1走
也可以离线后建出Tire,把1的孩子并到0的孩子上,1的孩子不变
简单考虑怎么做
设一个 F [ S ] F[S] F[S]表示对于所有 S a n d T = S SandT=S SandT=S即S为T的子集的所有T的最早出现位置
可以用一个DP求出来
仍然从大往小扫,如果当前位是1就直接加上 2 i 2^i 2i贡献
否则我们看看之前确定要填1的位置再加上当前要填1的位置组成的 S S S中是否有一个 T T T出现在当前这个数的左边,是的话就加上 2 i + 1 2^{i+1} 2i+1并记录这里填了1,否则不做操作
因为其他位是否是1都不影响答案,不需要考虑

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair
#define pii pair
using namespace std;
inline LL read()
{
	LL f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(LL x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=300005;
const int MAXM=1000005;
int f[8*MAXM],a[MAXN],n;
int bin[25];
int main()
{
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	bin[0]=1;for(int i=1;i<=22;i++)bin[i]=bin[i-1]<<1;
	n=read();
	memset(f,63,sizeof(f));
	for(int i=1;i<=n;i++)a[i]=read()^a[i-1],f[a[i]]=min(f[a[i]],i);
	for(int i=2*MAXM;i>=0;i--)
		for(int j=21;j>=0;j--)if(i&bin[j])f[i^bin[j]]=min(f[i^bin[j]],f[i]);
	pr2(a[1]);
	for(int i=2;i<=n;i++)
	{
		int ans=0,now=0;
		for(int j=21;j>=0;j--)
		{
			if(a[i]&bin[j])ans+=bin[j];
			else if(f[now|bin[j]]<=i)ans+=bin[j]*2,now|=bin[j];
		}
		pr2(ans);
	}
	return 0;
}

你可能感兴趣的:(bzoj,乱搞,贪心)