4513: [Sdoi2016]储能表
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 510 Solved: 266
[ Submit][ Status][ Discuss]
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
2 2 0 100
3 3 0 100
3 3 1 100
Sample Output
2
12
6
12
6
HINT
T=5000,n≤10^18,m≤10^18,k≤10^18,p≤10^9
Source
数位dp。。。每次看到这种东西就头疼= =
f[i][j][k][a][b]:第i位数字xor为j,是否大于k,是否小于n,是否小于m,数字之和
g[i][j][k][a][b]:第i位数字xor为j,是否大于k,是否小于n,是否小于m,数字的数量
转移的话。。。瞎逼讨论咯= =
建议后三位压在一起,用0~7表示
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 62;
typedef long long LL;
int T,f[N][2][8],g[N][2][8],a[N],b[N],c[N],mi[N];
LL n,m,k,p;
int Add(const LL &x,const LL &y) {return (x + y) % p;}
int Mul(const LL &x,const LL &y) {return x*y%p;}
int Dec(const LL &x,const LL &y) {return (x - y + p) % p;}
void Work(LL x,int *A)
{
for (int i = 0; i < N; i++)
A[N-i-1] = (x&1LL),x >>= 1LL;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> T;
while (T--)
{
scanf("%lld%lld%lld%lld",&n,&m,&k,&p);
mi[N-1] = 1;
for (int i = N-2; i >= 0; i--) mi[i] = Mul(mi[i+1],2);
Work(--n,a); Work(--m,b); Work(k,c);
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
g[0][0][0] = 1;
for (int i = 0; i < N - 1; i++)
for (int j = 0; j < 2; j++)
for (int l = 0; l < 8; l++)
{
if (!g[i][j][l]) continue;
for (int A = 0; A < 2; A++)
for (int B = 0; B < 2; B++)
{
if (!(l&2) && A > a[i+1]) continue;
if (!(l&4) && B > b[i+1]) continue;
int C = (A^B);
if (!(l&1) && C < c[i+1]) continue;
int f1,f2,f4,F;
if ((l&1) || (!(l&1) && C > c[i+1])) f1 = 1; else f1 = 0;
if ((l&2) || (!(l&2) && A < a[i+1])) f2 = 2; else f2 = 0;
if ((l&4) || (!(l&4) && B < b[i+1])) f4 = 4; else f4 = 0;
F = (f1|f2|f4);
g[i+1][C][F] = Add(g[i+1][C][F],g[i][j][l]);
int ADD = Mul(Mul(C,mi[i+1]),g[i][j][l]);
f[i+1][C][F] = Add(f[i+1][C][F],Add(ADD,f[i][j][l]));
}
}
int Ans = 0; k %= p;
for (int i = 0; i < 2; i++)
for (int j = 0; j < 8; j++)
{
Ans = Add(Ans,f[N-1][i][j]);
Ans = Dec(Ans,Mul(g[N-1][i][j],k));
}
printf("%d\n",Ans);
}
return 0;
}