[SDOI2016]储能表

Posted asuldb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SDOI2016]储能表相关的知识,希望对你有一定的参考价值。

题目

数位\(dp\)思博题啊

但是我更加思博啊

面对\(10^{18}\)的数据范围,我竟然只开了\(19\)的数据,而这是一道二进制数位\(dp\)

我们设\(f[i][0/1][0/1][0/1]\)表示进行到了第\(i\)位,不卡/卡\(n\)的上界,不卡/卡\(m\)的上界,不卡/卡\(k\)的下界,我们求出所有异或值大于\(k\)的数的和,和方案数随便搞一搞就出来了

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline LL read() {
    char c=getchar();LL x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int T;
LL n,m,K,mod;
LL dp[67][2][2][2],f[67][2][2][2],pw[67];
int a[67],b[67],c[67];
inline void countBit(LL x,int *g) {
    int tot=0;
    while(x) {g[tot++]=(x&1ll);x>>=1ll;}
}
int main() {
    T=read();
    while(T--) {
        n=read(),m=read(),K=read(),mod=read();
        if(n>m) std::swap(n,m);
        n--,m--;
        memset(dp,0,sizeof(dp));
        memset(f,0,sizeof(f));
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        memset(c,0,sizeof(c));
        memset(pw,0,sizeof(pw));
        pw[0]=1;
        for(re int i=1;i<=65;i++) pw[i]=(pw[i-1]+pw[i-1])%mod;
        countBit(n,a),countBit(m,b),countBit(K,c);
        f[66][1][1][1]=1;
        for(re int i=65;i>=0;--i)
            for(re int j=0;j<2;j++)
                for(re int k=0;k<2;k++)
                    for(re int p=0;p<2;p++) {
                        for(re int t=0;t<2;t++)
                            for(re int h=0;h<2;h++) {
                                if(j&&t>a[i]) continue;
                                if(k&&h>b[i]) continue;
                                if(p&&(t^h)<c[i]) continue;
                                int o1=j;
                                if(o1) if(t<a[i]) o1=0;
                                int o2=k;
                                if(o2) if(h<b[i]) o2=0;
                                int o3=p;
                                if(o3) if((t^h)>c[i]) o3=0;
                                f[i][o1][o2][o3]=(f[i][o1][o2][o3]+f[i+1][j][k][p])%mod;
                                dp[i][o1][o2][o3]=(dp[i][o1][o2][o3]+dp[i+1][j][k][p])%mod;
                                if(h^t) 
                                    dp[i][o1][o2][o3]=(dp[i][o1][o2][o3]+f[i+1][j][k][p]*pw[i]%mod)%mod;
                            }
                    }
        LL ans=0,cnt=0;
        for(re int i=0;i<2;i++)
            for(re int j=0;j<2;j++)
                for(re int k=0;k<2;k++)
                    ans=(ans+dp[0][i][j][k])%mod,cnt=(cnt+f[0][i][j][k])%mod;
        K%=mod;
        printf("%lld\n",(ans-cnt*K%mod+mod)%mod);   
    }
    return 0;
}

以上是关于[SDOI2016]储能表的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4513[Sdoi2016]储能表 数位DP

搜索(四分树):BZOJ 4513 [SDOI2016 Round1] 储能表

loj2030 「SDOI2016」储能表

BZOJ 4513: [Sdoi2016]储能表

bzoj 4513 [Sdoi2016]储能表

4513: [Sdoi2016]储能表 数位DP