[SDOI2016]储能表
数位dp题。
f[i][0/1][0/1][0/1]表示从高到低第i位,是否到n的上界,是否到m的上界,当前异或结果是否到k的下界。
对于每个状态记录合法方案数和所有合法i,j的异或和,对于每一位枚举n和m选0还是1转移即可。
#include<bits/stdc++.h>
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout);
#define N 2000000
#define inf 123456789123456789
#define db double
//#define P 1000000007
#define int long long
#define mid (l+r>>1)
#define d(x) (x>>cur-1&1)
using namespace std;
int n,m,k,P,T;
struct node{int x,y;}mp[70][2][2][2];
node dp(int cur,int nx,int mx,int kx){
if(!cur) return {1,0};
if(mp[cur][nx][mx][kx].x) return mp[cur][nx][mx][kx];
node res={0,0};
for(int i=0;i<=(d(n)||!nx);i++){
for(int j=0;j<=(d(m)||!mx);j++){
if(kx&&d(k)>(i^j)) continue;
node v=dp(cur-1,nx&&i==d(n),mx&&j==d(m),kx&&(i^j)==d(k));
(res.x+=v.x)%=P;
(res.y+=(((i^j)<<(cur-1))%P*v.x%P+v.y)%P)%=P;
}
}
return mp[cur][nx][mx][kx]=res;
}
signed main(){
scanf("%lld",&T);
while(T--){
memset(mp,0,sizeof(mp));
scanf("%lld%lld%lld%lld",&n,&m,&k,&P);n--;m--;
node v=dp(63,1,1,1);
printf("%lld\n",(v.y-k%P*v.x%P+P)%P);
}
return 0;
}
posted on 2020-07-08 22:59 啊啊啊起个什么名字好 阅读(123) 评论(0) 收藏 举报
浙公网安备 33010602011771号