枚举子集
二进制枚举子集下面代码就是枚举的s的子集(二进制状态压缩)
for(int i=s;i;i=(i-1)&s)
{
//i表示的就是s的子集
}
枚举所有子集的子集的时间复杂度
比如一个有n个元素构成的集合,子集的数量是 2 n 2^n 2n,现要求枚举所有子集的子集。
一个有k个元素构成的集合,子集的数量是 2 k 2^k 2k
考虑 n n n个元素构成的集合子集:
元素个数是 0 0 0的集合个数是 C n 0 C_n^0 Cn0
元素个数是 1 1 1的集合个数是 C n 1 C_n^1 Cn1
… \dots …
于是有以下等式
C n 0 × 2 0 + C n 1 × 2 n + ⋯ + C n n × 2 n = ( 1 + 2 ) n = 3 n C_n^0×2^0+C_n^1×2^n+\dots+C_n^n×2^n=(1+2)^n=3^n Cn0×20+Cn1×2n+⋯+Cnn×2n=(1+2)n=3n
由此最终需要枚举 3 n 3^n 3n个状态,时间复杂度为 Θ ( 3 n ) \Theta(3^n) Θ(3n)
Close Group
首先暴力预处理出所有满足题意的连通块,连通块中的点两两之间有直接边。 Θ ( n 2 + 2 n ) \Theta(n^2+2^n) Θ(n2+2n)
状态压缩dp
状态表式: f i f_i fi表示选择 i i i这些点构成的最少数量的团
状态计算:枚举 i i i状态的子集 j j j,于是有 f i = m i n ( f i , f j + f i ⊕ j ) f_i=min(f_i,f_j+f_{i\oplus j}) fi=min(fi,fj+fi⊕j)
时间复杂度:枚举所有状态的子集即上述证明 Θ ( 3 n ) \Theta(3^n) Θ(3n)
时间复杂度 Θ ( n 2 + 2 n + 3 n ) \Theta(n^2+2^n+3^n) Θ(n2+2n+3n)
3 18 = 387420489 3^{18}=387 420 489 318=387420489差不多能过,谁让状态压缩就是那么玄学呢
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=20;
bool ok[1<<N];
int g[N][N];
int dp[1<<N];
int main()
{
IO;
int T=1;
//cin>>T;
while(T--)
{
int n,m;
cin>>n>>m;
while(m--)
{
int a,b;
cin>>a>>b;
--a,--b;
g[a][b]=g[b][a]=1;
}
for(int i=0;i<1<<n;i++)
{
vector<int> t;
for(int j=0;j<n;j++)
if(i>>j&1) t.push_back(j);
ok[i]=1;
for(int j=0;j<t.size();j++)
for(int k=j+1;k<t.size();k++)
if(!g[t[j]][t[k]]) ok[i]=0;
}
for(int i=0;i<1<<n;i++) dp[i]=n+1;
dp[0]=0;
for(int i=1;i<1<<n;i++)
{
if(ok[i]) dp[i]=1;
for(int j=i;j;j=(j-1)&i)
dp[i]=min(dp[i],dp[j]+dp[j^i]);
}
cout<<dp[(1<<n)-1]<<'\n';
}
return 0;
}
E - Or Plus Max
对于K的子集一定满足 i o r j ≤ K i\ or\ j\leq K i or j≤K
枚举子集,记录子集的最大值和次大值,相加即可
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=500010;
int a[N];
int mx[N],f[N];
int main()
{
IO;
int T=1;
//cin>>T;
for(int ca=1;ca<=T;ca++)
{
int n;
cin>>n;
for(int i=0;i<1<<n;i++)
{
cin>>a[i];
mx[i]=a[0];
}
for(int i=0;i<1<<n;i++)
for(int j=i;j;j=(j-1)&i)
{
f[i]=max(f[i],a[j]+mx[i]);
mx[i]=max(mx[i],a[j]);
}
for(int i=1;i<1<<n;i++)
{
f[i]=max(f[i-1],f[i]);
cout<<f[i]<<'\n';
}
}
return 0;
}