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