SOSdp
作者:互联网
SOSdp
https://codeforces.ml/contest/383/problem/E
https://codeforces.ml/blog/entry/45223
E. Compatible Numbers
题意
给定 a i a_i ai,对每个数找到一个 a j a_j aj满足 a i & a j = 0 a_i\& a_j=0 ai&aj=0
思路
S O S d p SOS dp SOSdp
在原定义: f [ m a s k ] = ∑ i & m a s k = i a i f[mask]=\sum\limits_{i\&mask=i}a_i f[mask]=i&mask=i∑ai
将其修改为 f [ m a s k ] = f[mask]= f[mask]=属于 m a s k mask mask子集的其中一个数 a i a_i ai。
也就是把求和该为只保存一个数。
这样我们要求 a n s [ a i ] ans[a_i] ans[ai]就等价于求 f [ a l l ⊕ a i ] f[all\oplus a_i] f[all⊕ai], a l l = ( 2 20 − 1 ) all=(2^{20}-1) all=(220−1),所有位为 1 1 1。
时间复杂度: O ( N × 2 N ) O(N\times 2^N) O(N×2N)
注意初始化不存在情况为 − 1 -1 −1。
code
// Problem: E. Compatible Numbers
// Contest: Codeforces - Codeforces Round #112 (Div. 2)
// URL: https://codeforces.ml/contest/165/problem/E
// Memory Limit: 256 MB
// Time Limit: 4000 ms
// Date: 2021-03-13 15:01:57
// --------by Herio--------
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e6+5,M=1<<22,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\n",a[n]);
}
int f[M],n,a[N];
int main(){
scanf("%d",&n);mst(f,-1);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]),f[a[i]]=a[i];
}
//printf("%d %d\n",f[a[1]],f[a[2]]);
int st=1<<22;
for(int i=0;i<22;i++)
for(int j=0;j<st;j++){
if((j>>i&1)&&(~f[j^(1<<i)])) f[j]=f[j^(1<<i)];
}
for(int i=1;i<=n;i++)
printf("%d ",f[(st-1)^a[i]]);
return 0;
}
D. Jzzhu and Numbers
题意
给定 a i a_i ai,求满足子集按位与之和为 0 0 0的子集数。
思路
容斥原理+SOSdp
考虑令 a n s = ∣ W 1 ‾ ∩ W 2 ‾ ∩ W 3 ‾ ⋯ ∩ W k ‾ ∣ ans=|\overline{W_1}\cap\overline{W_2}\cap\overline{W_3}\dots\cap\overline{W_k}| ans=∣W1∩W2∩W3⋯∩Wk∣
W i W_i Wi表示二进制第 i i i位为1的方案数。(从第一位开始计算)
根据容斥原理: a n s = t o t − ∣ W 1 ‾ ∪ W 2 ‾ ∪ W 3 ‾ ⋯ ∪ W k ‾ ∣ ans=tot-|\overline{W_1}\cup\overline{W_2}\cup\overline{W_3}\dots\cup\overline{W_k}| ans=tot−∣W1∪W2∪W3⋯∪Wk∣
当为1的个数为奇数就是减,否则为加。
因为枚举位不好枚举,所以我们考虑枚举子集对应的情况。
即: f [ m a s k ] = ∑ m a s k & a i = a i ∣ S ∣ f[mask]=\sum\limits_{mask\&a_i=a_i}|S| f[mask]=mask&ai=ai∑∣S∣,即满足条件的 a i a_i ai个数。
这样答案就是 2 ∣ S ∣ − 1 2^{|S|}-1 2∣S∣−1个,因为不能一个不取,否则与运算为 0 0 0。
递推也与 S O S d p SOSdp SOSdp类似,具体看代码。
code
// Problem: D. Jzzhu and Numbers
// Contest: Codeforces - Codeforces Round #257 (Div. 1)
// URL: https://codeforces.ml/problemset/problem/449/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// Date: 2021-03-13 15:49:29
// --------by Herio--------
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=20,M=1<<20,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\n",a[n]);
}
int dp[M],n;
ll p[M],msk[M];
void init(int n){
p[0]=1;
for(int i=1;i<=n;i++) p[i]=p[i-1]*2%mod,msk[i]=msk[i&(i-1)]+1;
}
int main(){
scanf("%d",&n);
init(M-1);
for(int i=1,x;i<=n;i++){
scanf("%d",&x);dp[x]++;
}
for(int i=0;i<N;i++)
for(int j=0;j<M;j++) if(j>>i&1) dp[j^(1<<i)]+=dp[j];
ll ans=0;
for(int i=0;i<M;i++){
int f=(msk[i]&1)?-1:1;
ans=(ans+1LL*f*(p[dp[i]]-1))%mod;
}
printf("%lld\n",(ans%mod+mod)%mod);
return 0;
}
CCA的区间
题意
给定 n n n个 2 2 2的幂次数,至多翻转一次区间,求最大子区间和。
思路
至多翻转一次区间等价于求两个不相交区间的最大和,考虑 S O S d p SOSdp SOSdp,令 d p [ m a s k ] dp[mask] dp[mask]为属于 m a s k mask mask子集的最大答案。
然后对当前状态 i i i取反,即 a n s = m a x ( a n s , d p [ i ] + d p [ a l l ⊕ i ] ) ans=max(ans,dp[i]+dp[all\oplus i]) ans=max(ans,dp[i]+dp[all⊕i])即可。
时间复杂度: O ( N × 2 N ) O(N\times 2^N) O(N×2N)
code
// Problem: CCA的区间
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/11168/E
// Memory Limit: 524288 MB
// Time Limit: 4000 ms
// Date: 2021-03-13 16:39:09
// --------by Herio--------
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e5+5,M=1<<24,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\n",a[n]);
}
int a[N],n,dp[M];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
int x=0;
for(int j=i;j;j--){
if(x&a[j]) break;
x|=a[j];
dp[x]=x;
}
}
for(int i=0;i<24;i++)
for(int j=0;j<M;j++) if(j>>i&1) dp[j]=max(dp[j],dp[j^(1<<i)]);
int ans=0;
for(int i=0;i<M;i++) ans=max(ans,dp[i]+dp[(M-1)^i]);
printf("%d\n",ans);
return 0;
}
标签:int,mask,long,SOSdp,ans,dp,define 来源: https://blog.csdn.net/weixin_45750972/article/details/115425904