heyuhhh高维前缀和总结
SOS DP
SOS Dynamic Programming [Tutorial]
之前写过相关的题目枚举子集dp
枚举子集
F[mask]=∑i∈maskA[i],i&mask=iF[mask]=\sum_{i\in mask}A[i],i\&mask=iF[mask]=i∈mask∑A[i],i&mask=i
方法1,O(4n)O(4^n)O(4n)暴力枚举
for(int mask=0;mask<1<<N;mask++)for(int i=0;i<1<<n;i++)if(i&mask==i) F[mask]+=A[i];
方法2,O(3n)O(3^n)O(3n)枚举子集
for(int mask=0;mask<1<<N;mask++)
{F[mask]=A[0];for(int i=mask;i;i=(i-1)&mask)F[mask]+=F[i];
}
方法3,O(n×2n)O(n×2^n)O(n×2n)SOS dp
// 递推版本
for(int mask=0;mask<1<<N;mask++)
{dp[mask][-1]=A[mask];for(int i=0;i<N;i++){if(mask>>i&1) dp[mask][i]=dp[mask][i-1]+dp[mask^(1<<i)][i-1];elsedp[mask][i]=dp[mask][i-1];}F[mask]=dp[mask][N-1];
}
// 不难发现第二维状态可以滚动数组优化掉
for(int i=0;i<1<<N;i++) F[i]=A[i];
for(int i=0;i<N;i++)for(int mask=0;mask<1<<N;mask++)if(mask>>i&1)F[mask]+=F[mask^(1<<i)];
F. Bits And Pieces
issue敲腻害题解
fmaskf_{\text{mask}}fmask为mask\text{mask}mask的超集个数
iii是mask\text{mask}mask的超集说明mask&i=mask\text{mask}\&i=\text{mask}mask&i=mask
如果fmask≥2f_{\text{mask}}\ge 2fmask≥2说明存在aj&ak=maska_j\&a_k=maskaj&ak=mask
从后往前枚举aia_iai维护aj&aka_j\&a_kaj&ak
超集个数只需要在加入aia_iai时把它的所有子集个数加一即可。枚举子集可以利用SOS DP优化。
贪心从高位往低位选择即可。
#include<iostream>
#include<algorithm>
using namespace std;
constexpr int N=2000010;
int f[N],a[N],n;
void add(int x,int bit)
{if(f[x]>=2)return;if(bit<0) return f[x]++,void();add(x,bit-1);if(x>>bit&1) add(x^(1<<bit),bit-1);
}
int calc(int x)
{int ans=0,tmp=0;for(int i=20;i>=0;i--){if(x>>i&1) ans+=1<<i;else{if(f[tmp+(1<<i)]>=2) tmp+=1<<i,ans+=1<<i;}}return ans;
}
int main()
{ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);cin>>n;for(int i=1;i<=n;i++) cin>>a[i];int ans=0;for(int i=n;i>=1;i--){if(i<=n-2) ans=max(ans,calc(a[i]));add(a[i],20);}cout<<ans<<'\n';return 0;
}