Day1
T1 储能表
题目大意:已知n、m、k,求sigma(i=0~n-1,j=0~m-1)max((i^j)-k,0)。
思路:数位dp。fi[i][a][b][c]表示到第i位,和n、m的关系分别是a、b(0表示<,1表示=),和k的关系(0表示<,1表示=,2表示>)。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long #define N 100 using namespace std; LL n,m,k,p,fi[N][2][2][3],gi[N][2][2][3],c1,c2; int nn,ni[N],mi[N],ki[N]; void pre(){ int i,a,b,c;LL x; memset(ni,0,sizeof(ni)); memset(mi,0,sizeof(mi)); memset(ki,0,sizeof(ki)); for (i=0;i<N;++i) for (a=0;a<2;++a) for (b=0;b<2;++b) for (c=0;c<3;++c) fi[i][a][b][c]=gi[i][a][b][c]=0LL; for (x=n;x;x/=2LL) ni[++ni[0]]=x&1LL; for (x=m;x;x/=2LL) mi[++mi[0]]=x&1LL; for (x=k;x;x/=2LL) ki[++ki[0]]=x&1LL; nn=max(ni[0],max(mi[0],ki[0])); for (i=1;i<=nn/2;++i){ swap(ni[i],ni[nn-i+1]); swap(mi[i],mi[nn-i+1]); swap(ki[i],ki[nn-i+1]); } } void add(LL &x,LL y){x=(x+y)%p;} void work(){ int i,a,b,c,x,y,z,aa,bb,cc; c1=c2=0LL; gi[0][1][1][1]=1LL; for (i=0;i<nn;++i) for (a=0;a<2;++a) for (b=0;b<2;++b) for (c=0;c<3;++c){ if (gi[i][a][b][c]==0LL&&fi[i][a][b][c]==0LL) continue; for (x=0;x<2;++x){ if (a){ if (x>ni[i+1]) continue; if (x==ni[i+1]) aa=1; else aa=0; }else aa=0; for (y=0;y<2;++y){ if (b){ if (y>mi[i+1]) continue; if (y==mi[i+1]) bb=1; else bb=0; }else bb=0; z=x^y; if (c==0) cc=0; if (c==1){ if (z>ki[i+1]) cc=2; if (z==ki[i+1]) cc=1; if (z<ki[i+1]) cc=0; }if (c==2) cc=2; add(gi[i+1][aa][bb][cc],gi[i][a][b][c]); add(fi[i+1][aa][bb][cc],(fi[i][a][b][c]*2LL+(LL)z*gi[i][a][b][c])%p); } } } c1=fi[nn][0][0][2]; c2=gi[nn][0][0][2]; } int main(){ freopen("table.in","r",stdin); freopen("table.out","w",stdout); int t;LL ans; scanf("%d",&t); while(t--){ scanf("%I64d%I64d%I64d%I64d",&n,&m,&k,&p); pre();work(); ans=((c1-k%p*c2%p)%p+p)%p; printf("%I64d\n",ans); } }