本文主要是介绍[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<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
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;
}
这篇关于[bzoj5092][乱搞]分割序列的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!