[bzoj4513][数位DP]储能表

版权声明:蒻蒟的bolg... https://blog.csdn.net/Rose_max/article/details/85156125

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;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/85156125
今日推荐