卧薪尝胆,厚积薄发。
集合异或和
Date: Wed Aug 29 09:30:09 CST 2018 In Category: NoCategory

Description:

给定 $N$ 和 $M$ ,问有多少个集合 $X,Y$ 满足:
$1$ 、 $\forall x_i\in X,x_i\in[1,N]$ , $\forall y_i\in Y,y_i\in[1,M]$ 。
$2$ 、 $X\cap Y=\emptyset$
$3$ 、 $A=x_1\ xor\ x_2\ xor\dots xor\ x_n$ , $B=y_1\ xor\ y_2\ xor\dots xor\ y_m$ ,有 $A<B$
$1\le N,M\le 2000$

Solution:

对于前两个条件,含义就是说每个数只能出现在一个集合里,问题在于第三个限制怎么做,发现 $A<B$ 等价于在 $A$ 和 $B$ 最高不相同的位 $A=0$ 而 $B=1$ ,但是问题在于如何确定这个最高不相同的位,可以枚举这一位,由于 $\text{xor}$ 操作的特殊性质,可以设状态为 $f[i][j][0/1]$ 表示做到了第 $i$ 个数,当前 $A\ \text{xor}\ B$ 是 $j$ , $B$ 的第 $l$ 位为 $0/1$ 的方案数,转移时如果这个数给了 $A$ ,那么 $f[i][j\ \text{xor}\ i][0]+=f[i-1][j][0],f[i][j\ \text{xor}\ i][1]+=f[i-1][j][1]$ ,如果这个数给了 $B$ ,那么 $B$ 的第 $l$ 位可能改变,如果 $i$ 二进制下的第 $l$ 位是一,那么这个数给 $B$ 后 $B$ 的第 $l$ 位会发生变化,有转移: $f[i][j\ \text{xor}\ i][0]+=f[i-1][j][1],f[i][j\ \text{xor}\ i][1]+=f[i-1][j][0]$ ,否则 $B$ 不发生变化,有转移: $f[i][j\ \text{xor}\ i][0]+=f[i-1][j][0],f[i][j\ \text{xor}\ i][1]+=f[i-1][j][1]$ 。最后统计答案时,要求 $j$ 的最高位为 $l$ ,即 $j\in[2^l,2^{l+1})$ , $ans$ 应加上 $f[max(N,M)][j][1]$ 。 $j$ 的范围要预处理 $2$ 的幂然后一步步增加。
另外不要先加再 $\%=$ ,直接加的时候模会快很多。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n,m;
#define MAXN 2050
#define MOD 1000000007
int f[2][MAXN][2];
int bit[12];
int main()
{
scanf("%d%d",&n,&m);
register int ans = 0;
bit[0] = 1;
for(register int l = 1;l <= 11;++l)bit[l] = bit[l - 1] * 2;
for(register int l = 0;l <= 10;++l)
{
memset(f,0,sizeof(f));
register int cur = 0;
f[cur][0][0] = 1;
register int lim = 0;
for(register int i = 1;i <= max(n,m);++i)
{
cur ^= 1;
memset(f[cur],0,sizeof(f[cur]));
while(i >= bit[lim])++lim;
for(register int j = 0;j <= bit[lim];++j)
{
f[cur][j][0] = (f[cur][j][0] + f[cur ^ 1][j][0]) % MOD;
f[cur][j][1] = (f[cur][j][1] + f[cur ^ 1][j][1]) % MOD;
if(i <= n)
{
f[cur][j ^ i][0] = (f[cur][j ^ i][0] + f[cur ^ 1][j][0]) % MOD;
f[cur][j ^ i][1] = (f[cur][j ^ i][1] + f[cur ^ 1][j][1]) % MOD;
}
if(i <= m)
{
if(i & (1 << l))
{
f[cur][j ^ i][0] = (f[cur][j ^ i][0] + f[cur ^ 1][j][1]) % MOD;
f[cur][j ^ i][1] = (f[cur][j ^ i][1] + f[cur ^ 1][j][0]) % MOD;
}
else
{
f[cur][j ^ i][0] = (f[cur][j ^ i][0] + f[cur ^ 1][j][0]) % MOD;
f[cur][j ^ i][1] = (f[cur][j ^ i][1] + f[cur ^ 1][j][1]) % MOD;
}
}
}
}
for(register int j = (1 << l);j < (1 << (l + 1));++j)
{
ans = (ans + f[cur][j][1]) % MOD;
}
}
printf("%d\n",ans);
return 0;
}
In tag: DP-DP
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡