子序列 解题报告
子序列
題目描述
墊底哥學了兩年 OI 最近剛剛學會了 xor 和子序列。
他得到了一個長度為 \(n\) 的數組 \(a_1, a_2, a_3,\dots, a_n\),他想知道 xor 值為 \(0\) 的子序列最長是多少。
然而墊底哥除了墊底其它什么都不會,他就找你解決這個問題。
輸入格式
第一行一個正整數 \(n\)。
第二行 \(n\) 個整數,分別表示 \(a_1, a_2, a_3, \dots, a_n\)。
輸出格式
一行 \(1\) 個整數,表示答案。
數據規模與約定
對于所有數據,滿足 \(1 ≤ n ≤ 5 × 10^5, 0 ≤ a_i ≤ 5 × 10^5\)。
記 \(A = \max\{a_1, a_2, \cdots , a_n\}\):
? \(Subtask \ 1\)(\(10\%\)):\(n ≤ 20\);
? \(Subtask\ 2\)(\(20\%\)):\(n ≤ 100\),\(A ≤ 100\);
? \(Subtask 3\)(\(30\%\)):\(n ≤ 3000,A ≤ 3000\);
? \(Subtask 4\)(\(40\%\)):無特殊限制。
考慮補集轉換,設\(S=a_1\ xor \ a_2 \ xor \dots \ xor \ a_n\),求最少的可以異或出\(S\)的數的個數。
由線性姬的構造可以得到個數一定不大于\(\log A\)
然后可以DP一下,\(dp_{i,j}\)代表\(i\)個數是否可以異或出\(j\)
可以拿FWT優化這個轉移,直接裸優化是\(n\log^2A\)的,不過我們發現只需要單點詢問一個數是否有值就可以了,于是可以先正變換,然后每次單點做一次\(O(n)\)的逆變換
Code:
#include <cstdio> #define beelovely 2333 const int mod=998244353; #define add(a,b) (a+b>=mod?a+b-mod:a+b) #define mul(a,b) (1ll*(a)*(b)%mod) const int N=(1<<19)+10; int n,s,mx,a[N],popcnt[N],f[N],b[N],lim=1; void FWT(int *a) {for(int le=1;le<lim;le<<=1)for(int p=0;p<lim;p+=le<<1)for(int i=p;i<p+le;i++){int x=a[i],y=a[i+le];a[i]=add(x,y);a[i+le]=add(x,mod-y);} } int main() {scanf("%d",&n);for(int x,i=1;i<=n;i++) scanf("%d",&x),s^=x,++a[x],mx=mx>x?mx:x;while(lim<=mx) lim<<=1;for(int i=1;i<lim;i++){popcnt[i]=popcnt[i>>1]+(i&1);b[i]=popcnt[i]&1?mod-1:1;}f[0]=b[0]=1;FWT(a),FWT(f);while(beelovely){int dew=0;for(int i=0;i<lim;i++) dew=add(dew,mul(f[i],b[s&i]));if(dew) break;--n;for(int i=0;i<lim;i++) f[i]=mul(f[i],a[i]);}printf("%d\n",n);return 0; }2019.1.17
轉載于:https://www.cnblogs.com/butterflydew/p/10284431.html
總結
- 上一篇: IOS上微信在输入框弹出键盘后,页面不恢
- 下一篇: MySQL.