思路:
首先考虑暴力
DP
D
P
,
dp[i][a][b]
d
p
[
i
]
[
a
]
[
b
]
={
dp[i−1][a⊕i][b],dp[i−1][a][b⊕i],dp[i−1][a][b]
d
p
[
i
−
1
]
[
a
⊕
i
]
[
b
]
,
d
p
[
i
−
1
]
[
a
]
[
b
⊕
i
]
,
d
p
[
i
−
1
]
[
a
]
[
b
]
}
Θ(n3)
Θ
(
n
3
)
然后优化,首先考虑定义状态
dp[i][a−b]
d
p
[
i
]
[
a
−
b
]
这样虽然能反映两个数大小但是不好转移
所以考虑
dp[i][ab]
d
p
[
i
]
[
a
b
]
这样方便了转移但是·不容易反映大小,所以还要定义一个状态:第一个二进制中的1是在a中取到还是在b中取到,有转移:
if(j<=n) Add(dp[i+1][k^j][(j&(1<<i))?1-l:l],dp[i][k][l]);
if(j<=m) Add(dp[i+1][k^j][l],dp[i][k][l]);
Add(dp[i+1][k][l],dp[i][k][l]);
code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;i++)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define db double
#define LL long long
#define INF 0x3f3f3f3f
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
inline LL Max(LL &x,LL y){return x>y?x:y;}
inline LL Min(LL &x,LL y){return x<y?x:y;}
#define N 2052
#define M 12
#define mod 1000000007
void Add(LL &x,LL y){
x+=y;
if(x>=mod)x%=mod;
if(x<0)(x+=mod)%=mod;
}
LL dp[N][2],tmp[N][2];// dp[i][0/1]表示集合{A}^{B}==i,且0表示最高位在A,1表示最高位在B
class WinterAndSnowmen {
public:
int getNumber(int n, int m) {
LL ans=0;
SREP(i,0,M){
mcl(dp,0);
mcl(tmp,0);
dp[0][0]=1;
REP(j,1,max(n,m)){
mcl(tmp,0);
SREP(k,0,N) REP(l,0,1){
if(j<=n)Add(tmp[k^j][(j&(1<<i))?1-l:l],dp[k][l]);
if(j<=m)Add(tmp[k^j][l],dp[k][l]);
}
SREP(k,0,N) REP(l,0,1) Add(dp[k][l],tmp[k][l]);
}
SREP(j,0,N)if(j/(1<<i)==1)Add(ans,dp[j][0]);
}
return ans;
}
};