luoguP4310 絕世好題
阿新 • • 發佈:2020-12-04
題面簡述:
給定一個長度為 $ n $ 的數列 $ a_i $ ,求 $ a_i $ 的一個最長子序列 $ b_i $ (假設長度為 $ m $ ),滿足 $ b_{i} $ & $ b_{i+1} ≠ 0 ( 1 \leq i < k ) $ 。
資料範圍:$ 1 \leq n \leq 10^5 , 1 \leq a_i \leq 10^9 $ 。
題解:
有一個樸素的想法就是設 $ f_i $ 表示當前序列最後一個為 $ a_i $ 的長度的最大值,顯然這樣直接轉移是 $ O(n^2) $ 的。
考慮如何優化這個東西。注意到 $ b_{i} $ & $ b_{i+1} ≠ 0 $ 的條件就是它們兩個數在二進位制表示下在某一位上同為 $ 1 $ 。於是設 $ g_j $ 表示在第 $ j $ 位上為 $ 1 $ 的序列長度的最大值,列舉到每一位上轉移即可。時間複雜度 $ O( n log \max {a_i}) $ 。
#include <bits/stdc++.h> using namespace std; inline int read(){ int f=1,r=0;char c=getchar(); while(!isdigit(c))f^=c=='-',c=getchar(); while(isdigit(c))r=(r<<1)+(r<<3)+(c^48),c=getchar(); return f?r:-r; } const int N=1e5+5; int n,ans,g[33]; int main(){ n=read(); for(int i=1;i<=n;i++){ int x=read(),f=0; for(int j=30;~j;j--) if(x&(1<<j)) f=max(f,g[j]+1); for(int j=30;~j;j--)//由於上面是取最大值,所以這裡就不要再去取最大值了。 if(x&(1<<j))g[j]=f; ans=max(ans,f); } return cout<<ans,0; }