C. Boboniu and Bit Operations(状压)

一个超级显然的状压

可惜我昨天没打

这题有个很简单的思维解法,想看戳我哦,比状压简单很多

言归正传,反正思维的解法我没想到,用状压草过去的,状压毕竟具有普适性

定 义 d p [ i ] [ j ] 为 构 造 好 第 i 个 c i 后 , 前 i 个 c 元 素 相 或 运 算 是 否 可 能 得 到 二 进 制 j 定义dp[i][j]为构造好第i个c_i后,前i个c元素相或运算是否可能得到二进制j dp[i][j]ici,icj

这 个 j 的 范 围 就 是 [ 0 , 1 < < 9 ] 嘛 , 因 为 或 和 与 不 会 改 变 二 进 制 范 围 这个j的范围就是[0,1<<9]嘛,因为或和与不会改变二进制范围 j[0,1<<9],

那 么 对 于 当 前 的 a i , 枚 举 一 个 b q 构 造 成 此 时 的 c i 那么对于当前的a_i,枚举一个b_q构造成此时的c_i ai,bqci

再 来 一 层 f o r 循 环 枚 举 与 运 算 完 c i 后 的 二 进 制 j 再来一层for循环枚举与运算完c_i后的二进制j forcij

再 来 一 层 f o r 循 环 枚 举 二 进 制 d 表 示 要 从 d p [ i − 1 ] [ d ] 转 移 而 来 再来一层for循环枚举二进制d表示要从dp[i-1][d]转移而来 forddp[i1][d]

于是转移方程是

d p [ i ] [ j ] = d p [ i ] [ j ] dp[i][j]=dp[i][j] dp[i][j]=dp[i][j] | d p [ i − 1 ] [ d ] dp[i-1][d] dp[i1][d]

中间的竖线表示或运算

意 思 是 , 只 要 存 在 一 个 d 使 得 d p [ i − 1 ] [ d ] 可 行 , 那 么 d p [ i ] [ j ] 也 可 行 意思是,只要存在一个d使得dp[i-1][d]可行,那么dp[i][j]也可行 ,d使dp[i1][d],dp[i][j]

于是我们可以写下如下代码

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];
		 }
	}
}

拿起小拇指一算复杂度,哇呜呜

2 9 ∗ 2 9 ∗ 200 ∗ 200 = . . . . . . . . 2^9*2^9*200*200=........ 2929200200=........

但 是 仔 细 看 , 枚 举 d 的 那 个 循 环 , 很 多 工 作 是 不 需 要 的 但是仔细看,枚举d的那个循环,很多工作是不需要的 ,d,

现 在 已 知 s 和 j , 我 们 需 要 枚 举 的 都 是 s ∣ d = = j 的 那 些 d 现在已知s和j,我们需要枚举的都是s|d==j的那些d sj,sd==jd

d或运算s变成j

或运算嘛,只有当d没有某一位的二进制而s有这位二进制才会使得d的这一位变成1

但 是 贡 献 给 d 哪 几 位 二 进 制 呢 ? 但是贡献给d哪几位二进制呢? d?

对于s的某一位是1的二进制有选和不选两种可能

d f s 爆 搜 出 所 有 情 况 , 存 入 v e c 数 组 中 即 可 dfs爆搜出所有情况,存入vec数组中即可 dfs,vec

那 么 现 在 v e c 存 的 是 s 贡 献 给 d 的 二 进 制 那么现在vec存的是s贡献给d的二进制 vecsd

设 y 是 s 贡 献 给 d 的 二 进 制 数 , 那 么 d ∣ s = j 设y是s贡献给d的二进制数,那么d|s=j ysd,ds=j

解得 d = ( j 异 或 s ) d=(j异或s) d=(js)

当然这貌似属于sos枚举子集的状压,你有兴趣可以去搜一下

#include 
using namespace std;
int n,m,a[209],b[209];
int dp[209][1<<10];
vectorvec[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

你可能感兴趣的:(div题解)