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);
    }
}
View Code

相关文章: