JZOJ-senior-5952. 【NOIP2018模擬11.5A組】凱旋而歸
阿新 • • 發佈:2018-12-20
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);
}
}