2020 ccpc 网络赛 1012 Xor
题意:
数位DP
首先,为了方便表示,我们将 |x-y|<=K转化为 x+K>=y 且 y+K>=x。
此时,我们发现,如果用传统的从高位到低位的数位DP,我们无法处理x+K出现进位之后的情况,因此,我们考虑从低位到高位进行DP。
设F[now][opa][opb][opx][opy][dax][day][opw]为状态数组,
now 表示当前DP到了哪一位
opa 表示 x<=A
opb 表示 y<=B
opx 表示 x+K<=y
opy 表示 y+K<=x
dax 表示 now-1 位时 x+K 是否产生了进位
day 表示 now-1 位时 y+K 是否产生了进位
opw 表示 x^y<=w
之后,我们利用记忆化搜索,每次枚举now这一位上 x y是 0 还是 1 ,然后就可以算出opa等变量在now上的取值。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 long long F[35][2][2][2][2][2][2][2]; 9 int T,A,B,K,W; 10 long long dfs(int now,int opa,int opb,int opx,int opy,int dax,int day,int opw) 11 { 12 if(F[now][opa][opb][opx][opy][dax][day][opw]!=-1)return F[now][opa][opb][opx][opy][dax][day][opw]; 13 if(now==31) 14 { 15 if(opa&&opb&&opb&&(opx||dax)&&(opy||day)&&opw)return F[now][opa][opb][opx][opy][dax][day][opw]=1; 16 return F[now][opa][opb][opx][opy][dax][day][opw]=0; 17 } 18 int daa=(A>>now)&1,dab=(B>>now)&1; 19 int dak=(K>>now)&1,daw=(W>>now)&1; 20 F[now][opa][opb][opx][opy][dax][day][opw]=0; 21 for(int i=0;i<=1;i++) 22 { 23 for(int j=0;j<=1;j++) 24 { 25 int nopa,nopb,nopx,nopy,ndax,nday,nopw; 26 nopa=(opa&&i<=daa)||(!opa&&i<daa); 27 nopb=(opb&&j<=dab)||(!opb&&j<dab); 28 29 nopx=(opx&&((i+dax+dak)&1)>=j)||(!opx&&((i+dax+dak)&1)>j); 30 ndax=(i+dax+dak)>1; 31 32 nopy=(opy&&((j+day+dak)&1)>=i)||(!opy&&((j+day+dak)&1)>i); 33 nday=(j+day+dak)>1; 34 35 nopw=(opw&&(i^j)<=daw)||(!opw&&(i^j)<daw); 36 F[now][opa][opb][opx][opy][dax][day][opw]+=dfs(now+1,nopa,nopb,nopx,nopy,ndax,nday,nopw); 37 } 38 } 39 return F[now][opa][opb][opx][opy][dax][day][opw]; 40 } 41 int main() 42 { 43 scanf("%d",&T); 44 while(T--) 45 { 46 scanf("%d%d%d%d",&A,&B,&K,&W); 47 memset(F,-1,sizeof(F)); 48 printf("%lld\n",dfs(0,1,1,1,1,0,0,1)); 49 } 50 return 0; 51 }