一个超级显然的状压
可惜我昨天没打
言归正传,反正思维的解法我没想到,用状压草过去的,状压毕竟具有普适性
于是转移方程是
|
中间的竖线表示或运算
于是我们可以写下如下代码
dp[0][0]=1;
for(int i=1;i<=n;i++)
for(int q=1;q<=m;q++)
{
int s = (a[i]&b[q]) ;//当前构造的c[i]
for(int j=0;j<=(1<<9);j++)//本状态
{
if( (j&s)!=s ) continue;//本状态由于或上了c[i],二进制一定包含c[i]
for(int d=0;d<=j;d++)//上一状态d|s=j,所以不可能大于j
{
if( (d|s)!=j ) continue;
dp[i][j]|=dp[i-1][d];
}
}
}
拿起小拇指一算复杂度,哇呜呜
d或运算s变成j
或运算嘛,只有当d没有某一位的二进制而s有这位二进制才会使得d的这一位变成1
对于s的某一位是1的二进制有选和不选两种可能
解得
当然这貌似属于sos枚举子集的状压,你有兴趣可以去搜一下
#include <bits/stdc++.h>
using namespace std;
int n,m,a[209],b[209];
int dp[209][1<<10];
vector<int>vec[209][209];
void dfs(int bit,int temp,int i,int j,int he)
{
if( bit==(1<<9) )
{
vec[i][j].push_back(he);
return;
}
if( bit&temp )
{
dfs(bit*2,temp,i,j,he);
dfs(bit*2,temp,i,j,he+bit);
}
else dfs(bit*2,temp,i,j,he);;
}
int main()
{
cin >> n >> m;
for(int i=1;i<=n;i++) cin >> a[i];
for(int j=1;j<=m;j++) cin >> b[j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int temp = (a[i]&b[j]);
dfs(1,temp,i,j,0);//爆搜
}
dp[0][0]=1;
for(int i=1;i<=n;i++)
for(int q=1;q<=m;q++)
{
int s = (a[i]&b[q]) ;
for(int j=0;j<=(1<<9);j++)//本状态
{
if( (j&s)!=s ) continue;
for(int d=0;d<vec[i][q].size();d++)//直接枚举贡献哪些二进制
{
int last=(j^vec[i][q][d]);//上一个状态
dp[i][j]|=dp[i-1][last];
}
}
}
int ans=0;
for(int i=0;i<=(1<<9);i++)
if( dp[n][i])
{
cout << i;
return 0;
}
}