[SDOI2016]储能表——数位DP

挺隐蔽的数位DP。少见

其实减到0不减了挺难处理。。。。。然后就懵了。

其实换个思路:

xor小于k的哪些都没了,

只要留下(i^j)大于等于k的那些数的和以及个数,

和-个数*k就是答案

数位DP即可

f[i][0/1][0/1][0/1]表示,前i位,对n,m,k有无限制<=n,<=m,>=k?,xor值的总和

g[i][0/1][0/1][0/1]表示,前i位,对n,m,k有无限制<=n,<=m,>=k?,合法的方案数

然后枚举这一位的n,m数位填什么转移

注意爆int和爆long long:
1.1<<p爆int,这个还很大,必须立刻取模

2.最后tmp*k爆long long,k先对p取模

不稳啊~~

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define int long long
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(ll &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=66;
ll n,m,k;
ll mod;
ll f[N][2][2][2];
ll g[N][2][2][2];
int main(){    
    int t;
    rd(t);
    while(t--){
        scanf("%lld%lld%lld%lld",&n,&m,&k,&mod);
        --n;--m;
        memset(g,0,sizeof g);memset(f,0,sizeof f);
        g[61][1][1][1]=1;        
        for(reg p=60;p>=0;--p){
            int nn=(n>>p)&1LL,nm=(m>>p)&1LL,nk=(k>>p)&1LL;
        //    cout<<" wei "<<p<<endl;
        //    cout<<nn<<" "<<nm<<" "<<nk<<endl;
            for(reg i=0;i<=1;++i){//i
                for(reg j=0;j<=1;++j){//j
                    for(reg l=0;l<=1;++l){//lim n
                        for(reg r=0;r<=1;++r){//lim m
                            for(reg o=0;o<=1;++o){//lim k
                                if((l&&i>nn)||(r&&j>nm)||(o&&((i^j)<nk))) continue;
                                (f[p][((!l)||(i<nn))?0:1][((!r)||(j<nm))?0:1][((!o)||((i^j)>nk))?0:1]+=(f[p+1][l][r][o]+(ll)(i^j)*(1LL*1<<p)%mod*g[p+1][l][r][o]%mod)%mod)%=mod;
                                (g[p][((!l)||(i<nn))?0:1][((!r)||(j<nm))?0:1][((!o)||((i^j)>nk))?0:1]+=(g[p+1][l][r][o]))%=mod;
                            }
                        }
                    }
                }
            }
        }
        ll ans=0;
        ll tmp=0;
        for(reg l=0;l<=1;++l){//lim n
            for(reg r=0;r<=1;++r){//lim m
                for(reg o=0;o<=1;++o){//lim k
                    (ans+=f[0][l][r][o])%=mod;
                    (tmp+=g[0][l][r][o])%=mod;    
                }
            }
        }
        k%=mod;
        ans=(ans%mod-tmp%mod*k%mod+mod)%mod;
        printf("%lld
",ans%mod);
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/2/26 18:48:55
*/

如果想到统计<=k的和和个数的话,就是一个限制比较多(维度多)的数位DP罢了。

原文地址:https://www.cnblogs.com/Miracevin/p/10439639.html