1. 程式人生 > >[bzoj4513][數位DP]儲能表

[bzoj4513][數位DP]儲能表

Description

有一個 n 行 m 列的表格,行從 0 到 n−1 編號,列從 0 到 m−1 編號。每個格子都儲存著能量。最初,第 i 行第 j
列的格子儲存著 (i xor j) 點能量。所以,整個表格儲存的總能量是,

在這裡插入圖片描述
隨著時間的推移,格子中的能量會漸漸減少。一個時間單位,每個格子中的能量都會減少 1。顯然,一個格子的能量減少到 0 之後就不會再減少了。
也就是說,k 個時間單位後,整個表格儲存的總能量是,
在這裡插入圖片描述
給出一個表格,求 k 個時間單位後它儲存的總能量。 由於總能量可能較大,輸出時對 p 取模。

Input

第一行一個整數 T,表示資料組數。接下來 T 行,每行四個整數 n、m、k、p。

Output

共 T 行,每行一個數,表示總能量對 p 取模後的結果

Sample Input

3

2 2 0 100

3 3 0 100

3 3 1 100

Sample Output

2

12

6

HINT

T=5000,n≤1018,m≤1018,k≤1018,p≤109

題解

文化課太多傷腦啊…
這種異或的題感覺就很數位dp嘛
維護四個值
位置 n是否頂格 m是否頂格 k是否頂格
每個位置列舉i,j填什麼轉移
然後 其實記憶化一下就可以了
因為後面和前面是沒有關係的呀…

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int> using namespace std; inline LL read() { LL f=1,x=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int stack[20]; inline void write(int x) { if(x<0){putchar('-');x=-x;} if(!x){putchar('0');return;} int top=0; while(x)stack[++top]=x%10,x/=10; while(top)putchar(stack[top--]+'0'); } inline void pr1(int x){write(x);putchar(' ');} inline void pr2(int x){write(x);putchar('\n');} LL mod,n,m,K; LL bin[75]; pll f[75][2][2][2],novis; int temp[3][75],ln[3]; void gets(LL x,int op) { ln[op]=0; while(x)temp[op][++ln[op]]=(x&1),x>>=1; } void ad(LL &x,LL y){x+=y;if(x>=mod)x-=mod;} pll dp1(int p,int op1,int op2,int op3)//0 頂格 1 不頂格 { if(!p) { if(op3)return mp(1,0); return mp(0,0); } if(f[p][op1][op2][op3]!=novis)return f[p][op1][op2][op3]; int lim1=op1?1:temp[0][p],lim2=op2?1:temp[1][p],lim3=op3?0:temp[2][p]; pll ret=mp(0,0); for(int i=0;i<=lim1;i++)for(int j=0;j<=lim2;j++)if((i^j)>=lim3) { pll num=dp1(p-1,op1|(i!=lim1),op2|(j!=lim2),op3|((i^j)>lim3)); ad(ret.first,num.first);ad(ret.second,num.second); ad(ret.second,((LL)i^j)*bin[p]*num.first%mod); } return f[p][op1][op2][op3]=ret; } int main() { novis=mp(-1,-1); int T=read();while(T--) { n=read()-1;m=read()-1;K=read();mod=read(); bin[1]=1;for(int i=2;i<=70;i++)bin[i]=(bin[i-1]<<1)%mod; // for(int i=1;i<=70;i++)pr2(bin[i]); memset(temp,0,sizeof(temp)); gets(n,0);gets(m,1);gets(K,2); for(int i=0;i<=70;i++)for(int j=0;j<=1;j++)for(int k=0;k<=1;k++)for(int l=0;l<=1;l++)f[i][j][k][l]=novis; int oo=max(ln[0],max(ln[2],ln[1])); pll aa=dp1(oo,0,0,0); LL ans=aa.second; ans=(ans-aa.first*(K%mod)%mod+mod)%mod; pr2(ans); } return 0; }