NC21620. 牛牛xor牛妹
描述
牛牛有一个集合{1,2,...,N}
牛妹有一个集合{1,2,...,M}
牛牛要从自己的集合里面选出一个子集,牛妹也一样
要求两个人选出的子集交集为空并且牛牛的子集的xor和小于牛妹的子集的xor和
求他们一共可以选择多少不同对的子集,模1e9+7
输入描述
输入一行包含两个整数n,m (1<=n,m<=2000)
输出描述
输出一个整数
示例1
输入:
2 2
输出:
4
示例2
输入:
47 74
输出:
962557390
C++14(g++5.4) 解法, 执行用时: 389ms, 内存消耗: 620K, 提交时间: 2020-06-25 16:58:41
#include<bits/stdc++.h> using namespace std; const int N = 2048; const int mod = 1e9 + 7; int dp[2][N][2]; void add(int &a, int b){ a += b; if(a >= mod) a -= mod; } int main(){ int n, m; scanf("%d %d", &n, &m); int l = max(n, m); int ans = 0; for(int P=11; P>=0; P--){ memset(dp, 0, sizeof(dp)); dp[0][0][0] = 1; for(int i=1; i<=l; i++){ for(int j=0; j<N; j++){ dp[1][j][0] = dp[0][j][0]; dp[1][j][1] = dp[0][j][1]; } for(int j=0; j<N; j++){ if(i <= n){ add(dp[1][j^i][0], dp[0][j][0]); add(dp[1][j^i][1], dp[0][j][1]); } if(i <= m){ if(i >> P & 1){ add(dp[1][j^i][1], dp[0][j][0]); add(dp[1][j^i][0], dp[0][j][1]); } else { add(dp[1][j^i][0], dp[0][j][0]); add(dp[1][j^i][1], dp[0][j][1]); } } } swap(dp[0], dp[1]); } for(int i=0; i<N; i++){ if((i >> P) == 1){ add(ans, dp[0][i][1]); } } } printf("%d\n", ans); return 0; }
C++11(clang++ 3.9) 解法, 执行用时: 481ms, 内存消耗: 504K, 提交时间: 2019-12-11 19:47:05
#include<bits/stdc++.h> #define ll long long using namespace std; const int p=1e9+7; int nt,pr,mx,ans,n,m,i,j,x,op,l,k,hh,ha,f[2][2048][2][2]; int main(){ scanf("%d%d",&n,&m); hh=max(n,m); for(op=0;;op++){ if((1<<op)>hh)break; mx=hh>>op; for(j=0;j<=min(2047,mx*2);j++) for(l=0;l<2;l++) for(k=0;k<2;k++)f[0][j][l][k]=0; f[0][0][0][0]=1; for(i=1;i<=hh;i++){ nt=i&1;pr=nt^1; for(j=0;j<=min(2047,mx*2);j++) for(l=0;l<2;l++) for(k=0;k<2;k++)f[nt][j][l][k]=0; x=i>>op;ha=x&1; for(j=0;j<=min(2047,mx*2);j++) for(l=0;l<2;l++) for(k=0;k<2;k++){ (f[nt][j][l][k]+=f[pr][j][l][k])%=p; if(i<=m)(f[nt][j^x][l][k^ha]+=f[pr][j][l][k])%=p; if(i<=n)(f[nt][j^x][l^ha][k]+=f[pr][j][l][k])%=p; } } ans=(ans+f[nt][1][0][1])%p; //printf("%d %d\n",nt,ans); } printf("%d",ans); }