2020.7.23 T1同余(jz暑假训练day8)

Description

在这里插入图片描述

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

2
1 1 5 100
3
2 0 7 7
2 2

Sample Output

16
0

Data Constraint

在这里插入图片描述

正解

dp,对于c,可以发现c在1至p-1之间时方案个数是一样的,所以c为多少不用考虑,只要判断是否为0就行了,然后我们设d[i][1]表示不是0的个数,d[i][0]表示是0的个数,然后d[i][1]=p-1^a[i]-1 d[i][0]就是总共的(p^a[i])-不是0的个数(p-1 ^ a[i]),然后就可以设出方程了。

#include<cstdio>
#include<cstring>
#define N 50007
using namespace std;
int t,n,c,d[N][2],a[N];
long long p,m,f[N],g[N],all[N];
long long fast(long long x,int y){//快速幂加速
	long long ans=1;
	while(y){
		if(y%2==1)
			ans=(ans*x)%m;
		x=(x*x)%m;
		y/=2;
	}
	return ans;
}
void get(int i,int x){//预处理出d
	d[i][1]=fast(p-1,x-1);
	d[i][0]=((fast(p,x)-(d[i][1]*(p-1))%m)+m)%m;
}
int main(){
	freopen("congruence.in","r",stdin);
	freopen("congruence.out","w",stdout);
	scanf("%d",&t);
	while(t--){
		memset(f,0,sizeof(f));
		memset(g,0,sizeof(g));
		memset(all,0,sizeof(all));
		memset(d,0,sizeof(d));
		scanf("%d%d%lld%lld",&n,&c,&p,&m);
		for(int i=1;i<=n;i++)
			scanf("%d",&a[i]),get(i,a[i]);
		all[0]=1;//f[i]指到第i个单项式时,答案刚好为c的方案,g[i]是不是c的方案,all指目前总共的方案
		if(c==0) f[0]=1,g[0]=0;
		else f[0]=0,g[0]=1;//初始化就自行思考
		for(int i=1;i<=n;i++){
			f[i]=(g[i-1]*d[i][1])%m+(f[i-1]*d[i][0])%m;//f[i]可以是i-1中不是c的方案加上一个特定的数(也就是前面);或者是i-1中是c的方案+0
			f[i]%=m;
			all[i]=all[i-1]*(d[i][0]+(d[i][1]*(p-1))%m)%m;//总方案求一下
			all[i]%=m;
			g[i]=all[i]-f[i];//总方案减去答案刚好为c的
			g[i]=(g[i]%m+m)%m;
		}
		printf("%lld\n",f[n]);
	}
}

猜你喜欢

转载自blog.csdn.net/jay_zai/article/details/107562099
今日推荐