1. 程式人生 > >JZOJ-senior-5952. 【NOIP2018模擬11.5A組】凱旋而歸

JZOJ-senior-5952. 【NOIP2018模擬11.5A組】凱旋而歸

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

記字首異或和為 bib_i ,則要求 bj+(bixorb

j)b_j+(b_i xor b_j) (j&lt;=ij&lt;=i) 的最大值 對 bib_i 拆位進行考慮 假如 bib_i 某一位為1,那麼無論 bjb_j 這一位是 00 還是 11 ,進行上述式子以後均為 11 所以 bjb_j 對這一位不會有任何貢獻,所以我們只關心 bib_i 二進位制下為 00 的位 不難發現,在 kk 位取 11 會比在 kk 位小的位全取 11 優 所以我們採取貪心的策略,只要前面可以取 11 就取,從高位往低位貪心 記 fif_i 表示滿足 ii a
ndand
bjb_j =i=i 的最小的 jj ,即 bjb_j 的子集有 ii 記當前找到的可以填充進去的數為 nownow 我們想把第 kk 位的貢獻從 02k10*2^{k-1} 變成 22k12*2^{k-1} 只需要判斷 fnow2k1f_{now|2^{k-1}} 是否小於等於 ii 若是,則 now=2k1now|=2^{k-1} ,貢獻便多了 22k12*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); } }