然后就可以轻松转移辣~\(≧▽≦)/~。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<set> #include<algorithm> #include<cmath> #include<cstdlib> #define ll long long #define N 105 using namespace std; ll n,m,k; int p,lenm,lenn,lenk,len,a[N],b[N],c[N],f[N][2][2][2],g[N][2][2][2],bin[N]; void ad(int &x,int y){ x+=y; if (x>=p) x-=p; } int main(){ int cas,i,x,y,z; scanf("%d",&cas); while (cas--){ scanf("%lld%lld%lld%d",&m,&n,&k,&p); memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); lenm=0; for (; m; m>>=1) a[++lenm]=m&1; lenn=0; for (; n; n>>=1) b[++lenn]=n&1; lenk=0; for (; k; k>>=1) c[++lenk]=k&1; len=max(max(lenm,lenn),lenk); bin[0]=1; for (i=1; i<=len; i++) bin[i]=(bin[i-1]<<1)%p; int i,j,k,l,x,y,z,u,v,tmp; memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); for (x=0; x<2; x++) for (y=0; y<2; y++) for (z=0; z<2; z++) for (u=0; u<((x)?2:a[1]); u++) for (v=0; v<((y)?2:b[1]); v++) if ((u^v)>=c[1] || z){ ad(f[1][x][y][z],((u^v)-c[1]+p)%p); ad(g[1][x][y][z],1); } for (i=2; i<=len; i++) for (x=0; x<2; x++) for (y=0; y<2; y++) for (z=0; z<2; z++) for (u=0; u<=max(x,a[i]); u++) for (v=0; v<=max(y,b[i]); v++) if ((u^v)>=c[i] || z){ j=x|(u<a[i]); k=y|(v<b[i]); l=z|((u^v)>c[i]); tmp=(ll)g[i-1][j][k][l]*((u^v)-c[i])*bin[i-1]%p; if (tmp<0) tmp+=p; ad(tmp,f[i-1][j][k][l]); ad(f[i][x][y][z],tmp); ad(g[i][x][y][z],g[i-1][j][k][l]); } printf("%d\n",f[len][0][0][0]); } return 0; }
by lych
2016.4.21