51nod 1301 集合异或和(DP)

因为当(A<B)时,会存在在二进制下的一位,满足这一位B的这一位是(1)(A)的这一位是(0).
我们枚举最大的这一位。设为(x)吧。
设计状态。(dp[i][j][1/0])代表考虑了前i个数,异或和为j的情况下(B)的第(x)位为(1)(0)有多少种情况。
然后随便转移一下,再随便统计答案一下就好了。
如果不知道如何转移,就看代码吧。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
int n,m,mx,dp[2100][2100][2],ans;
int read(){
	int sum=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
	return sum*f;
}
int main(){
	n=read();m=read();
	mx=max(n,m);
	int now=0;
	for(int i=1;i<=mx;i<<=1){
		now++;
		memset(dp,0,sizeof(dp));
		dp[0][0][0]=1;
		for(int j=1;j<=mx;j++){
			for(int k=0;k<=2047;k++){
				if(j<=m){
					dp[j][k][0]=(dp[j][k][0]+dp[j-1][k^j][0^((j&i)>>(now-1))])%mod;
					dp[j][k][1]=(dp[j][k][1]+dp[j-1][k^j][1^((j&i)>>(now-1))])%mod;
				}
				if(j<=n){
					dp[j][k][0]=(dp[j][k][0]+dp[j-1][k^j][0])%mod;
					dp[j][k][1]=(dp[j][k][1]+dp[j-1][k^j][1])%mod;
				}
				dp[j][k][0]=(dp[j][k][0]+dp[j-1][k][0])%mod;
				dp[j][k][1]=(dp[j][k][1]+dp[j-1][k][1])%mod;
			}
		}
		for(int j=i;j<=min(i*2-1,2047);j++)ans=(ans+dp[mx][j][1])%mod;
	}
	printf("%d",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/Xu-daxia/p/10479755.html