【BZOJ5092】分割序列(高维前缀和)

题意:对于一个长度为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的每个前缀的能量值。

n<=3e5,0<=a[i]<=1e6

思路:补ccpc的题被卡了,导致5h比赛后面2h都没了,查题解发现要用高维前缀和,先刷几题了解一下

实际上对于i,预处理前缀xor和数组s,答案就是max s[i]+s[i]^s[j]

考虑从高到低逐位确定

如果s[i]当前位为1,则不管s[j]当前位为0或1贡献都是2^j

如果s[i]当前位为0,则s[j]当前位为1的贡献是2^(j+1),当前位为0的贡献是0

考虑如何快速判断是否存在高位不劣,当前位为1,低位随意的s[j](即超集)

预处理一个数组f[i],f[i]表示对于所有j,i是0的位置j是0/1,i是1的位置j是1,所有合法的j的最小出现下标

直接判断f[now+2^j]是否<=i即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 typedef unsigned int uint;
 5 typedef unsigned long long ull;
 6 typedef pair<int,int> PII;
 7 typedef pair<ll,ll> Pll;
 8 typedef vector<int> VI;
 9 typedef vector<PII> VII;
10 //typedef pair<ll,ll>P;
11 #define N  310000
12 #define M  2000010
13 #define fi first
14 #define se second
15 #define MP make_pair
16 #define pb push_back
17 #define pi acos(-1)
18 #define mem(a,b) memset(a,b,sizeof(a))
19 #define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
20 #define per(i,a,b) for(int i=(int)a;i>=(int)b;i--)
21 #define lowbit(x) x&(-x)
22 #define Rand (rand()*(1<<16)+rand())
23 #define id(x) ((x)<=B?(x):m-n/(x)+1)
24 #define ls p<<1
25 #define rs p<<1|1
26 
27 const ll MOD=1e9+7,inv2=(MOD+1)/2;
28       double eps=1e-6;
29       int INF=1e9;
30       int dx[4]={-1,1,0,0};
31       int dy[4]={0,0,-1,1};
32 
33 int f[M],a[N];
34 
35 int read()
36 {
37    int v=0,f=1;
38    char c=getchar();
39    while(c<48||57<c) {if(c=='-') f=-1; c=getchar();}
40    while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
41    return v*f;
42 }
43 
44 int main()
45 {
46     int S=1<<20;
47     rep(i,0,S) f[i]=INF;
48     int n=read();
49     rep(i,1,n)
50     {
51         a[i]=read();
52         a[i]^=a[i-1];
53         f[a[i]]=min(f[a[i]],i);
54     }
55     rep(i,0,19)
56      rep(j,0,S-1)
57       if(!(j>>i&1)) f[j]=min(f[j],f[j^(1<<i)]);
58     rep(i,1,n)
59     {
60         int ans=0,now=0;
61         per(j,19,0)
62          if(a[i]>>j&1) ans+=(1<<j);
63           else
64           {
65               if(f[now^(1<<j)]<=i) ans+=(1<<(j+1)),now^=(1<<j);
66           }
67         printf("%d
",ans);
68     }
69     return 0;
70 }
原文地址:https://www.cnblogs.com/myx12345/p/11727922.html