[bzoj4513][數位DP]儲能表
阿新 • • 發佈:2018-12-24
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;
}