#include"bits/stdc++.h" #define re register #define int long long #define pii pair<int,int> #define fi first #define se second usingnamespace std; constint maxn=(1<<18)+10,inf=1e18; int n,S; pii f[maxn]; inlinevoidupd(pii &a,pii b){ if(b.fi>a.fi) a.se=max(a.fi,b.se),a.fi=b.fi; else a.se=max(a.se,b.fi); } signedmain(){ #ifndef ONLINE_JUDGE freopen("1.in","r",stdin); freopen("1.out","w",stdout); #endif ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n;S=(1<<n)-1; for(re int i=0;i<=S;++i) cin>>f[i].fi,f[i].se=-inf; for(re int i=0;i<n;++i){ for(re int s=0;s<=S;++s){ if((s>>i)&1) upd(f[s],f[s^(1<<i)]); } } int ans=0; for(re int i=1;i<=S;++i) ans=max(ans,f[i].fi+f[i].se),cout<<ans<<'\n'; return0; }
#include"bits/stdc++.h" #define re register #define int long long usingnamespace std; constint maxn=(1<<24)+10,m=24,S=(1<<24)-1; int n; int f[maxn]; signedmain(){ #ifndef ONLINE_JUDGE freopen("1.in","r",stdin); freopen("1.out","w",stdout); #endif ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n;char c; for(re int i=1;i<=n;++i){ int t=0,cnt=0; for(re int j=1;j<=3;++j) cin>>c,t|=(1<<(c-'a')); for(re int s=t;s;s=(s-1)&t){ if(__builtin_popcountll(s)&1) ++f[s]; else --f[s]; } } for(re int i=0;i<m;++i){ for(re int s=0;s<=S;++s){ if((s>>i)&1) f[s]+=f[s^(1<<i)]; } } int ans=0; for(re int s=0;s<=S;++s) ans^=(f[s]*f[s]); cout<<ans; return0; }
拓展
子集和能做,超集和呢?
事实上也很简单,子集和时我们是子集向自己贡献,那超集和只需要自己向子集贡献即可。
1 2 3 4 5
for(re int i=0;i<n;++i){ for(re int s=0;s<(1<<n);++s){ if((s>>i)&1) f[s^(1<<i)]+=f[s]; } }
前缀和能做,差分呢?
只需要符号变一下就行了。
也不难理解,毕竟前缀和的逆运算就是差分。
1 2 3 4 5
for(re int i=0;i<n;++i){ for(re int s=0;s<(1<<n);++s){ if((s>>i)&1) f[s]-=f[s^(1<<i)]; } }