bzoj4513: [Sdoi2016]储能表

看到带sigema的不要想着就是数论,也可以是数位DP啊

讨论的时候多利用for循环,不然讨论到自闭

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL n,m,K,mod;
int len[3],a[3][70],maxbit;
void divi(LL x,int w)
{
    len[w]=0; memset(a[w],0,sizeof(a[w]));
    while(x!=0)
    {
        a[w][++len[w]]=x%2;
        x/=2;
    }
}

LL Bin[70];
LL f[70][2][2][2],g[70][2][2][2];
void dfs(int k,int u,int v,int w)
{
    if(f[k][u][v][w]!=-1)return ;
    if(k==0){f[k][u][v][w]=0,g[k][u][v][w]=1;return ;}
    
    int bu=((u==0)||(a[0][k]==1));
    int bv=((v==0)||(a[1][k]==1));
    int bw=((w==1)&&(a[2][k]==1));
    
    f[k][u][v][w]=0;
    for(int i=0;i<=bu;i++)
        for(int j=0;j<=bv;j++)
            if((i^j)>=bw)
            {
                int tu=((u==1)&&(i==bu));
                int tv=((v==1)&&(j==bv));
                int tw=((w==1)&&((i^j)==bw));
                dfs(k-1,tu,tv,tw);
                f[k][u][v][w]=(f[k][u][v][w]+f[k-1][tu][tv][tw]+Bin[k]*(i^j)*g[k-1][tu][tv][tw])%mod;
                g[k][u][v][w]=(g[k][u][v][w]+g[k-1][tu][tv][tw])%mod;
            }
}

int main()
{
//    freopen("a.in","r",stdin);
//    freopen("a.out","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld%lld%lld",&n,&m,&K,&mod);n--,m--;
        divi(n,0),divi(m,1),divi(K,2);
        if(len[2]>len[0]&&len[2]>len[1]){puts("0");continue;}
        
        maxbit=max(len[0],len[1]);
        Bin[1]=1;for(int i=2;i<=maxbit;i++)Bin[i]=Bin[i-1]*2%mod;
        memset(f,-1,sizeof(f));
        memset(g,0,sizeof(g));
        dfs(maxbit,1,1,1);        
        printf("%lld\n",((f[maxbit][1][1][1]-g[maxbit][1][1][1]*(K%mod))%mod+mod)%mod);
    }
    
    return 0;
}

 

posted @ 2019-03-17 16:24  AKCqhzdy  阅读(93)  评论(0编辑  收藏  举报