码迷,mamicode.com
首页 > 其他好文 > 详细

P3321 [SDOI2015]序列统计

时间:2021-02-05 10:55:19      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:code   turn   line   quic   ring   快速幂   red   lag   eve   

中文题面
题解:记模m的原根为yg,yg的i次幂mod m(0<=i<=p-2)与1到p-1是有一个一一对应关系的,如果我们相求ab%mod=c%mod,我们可以把a和b换算为对应的\({yg}^{a1}\)\({yg}^{b1}\) = \({yg}^{c1}\),即\({yg}^{(a1+b1)mod(m-1)}\)=\({yg}^{c1}\),因为\({yg}^{(m-1)}\)=1(mod m),相当于(a1+b1)%(m-1)=c1,用对应的数代替一下给出数列里面的数,然后快速幂+fft就行了

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long
#define ll long long
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<‘ ‘; puts("");
using namespace std;
const int maxn = 32005,maxm = 320005,INF = 1000000000;
const int G = 3,P = 1004535809;
ll n,m,x,s,z;
int L,R[maxn];
LL A[maxn],B[maxn];
ll qpow(ll a,ll b){
	ll ans = 1;
	for (; b; b >>= 1,a = 1ll * a * a % P)
		if (b & 1) ans = 1ll * ans * a % P;
	return ans;
}
void NTT(ll* a,int f){
	for (int i = 0; i < z; i++) if (i < R[i]) swap(a[i],a[R[i]]);
	for (int i = 1; i < z; i <<= 1){
		int gn = qpow(G,(P - 1) / (i << 1));
		for (int j = 0; j < z; j += (i << 1)){
			int g = 1;
			for (int k = 0; k < i; k++,g = 1ll * g * gn % P){
				int x = a[j + k],y = 1ll * g * a[j + k + i] % P;
				a[j + k] = (x + y) % P; a[j + k + i] = (x - y + P) % P;
			}
		}
	}
	if (f == 1) return;
	int nv = qpow(z,P - 2); reverse(a + 1,a + z);
	for (int i = 0; i < z; i++) a[i] = 1ll * a[i] * nv % P;
}
ll yz[50];
ll quickpow(ll a,ll b,ll mod){
	ll ans=1;
	while(b!=0){
		if(b%2==1)ans=ans*a%mod;
		a=a*a%mod;
		b=b/2;
	}
	return ans;
}
ll getroot(ll x){
	x=x-1;
	int cnt=0;
	int temp=x;
	for(int i=2;i*i<=temp;i++){
		if(temp%i==0){
			yz[++cnt]=i;
			while(temp%i==0)temp=temp/i;
		}
	}
	if(temp>1)yz[++cnt]=temp;
	for(int i=2;i<=x;i++){
		int flag=0;
		for(int j=1;j<=cnt;j++){
			if(quickpow(i,x/yz[j],x+1)==1){
				flag=1;
				break;
			}
		}
		if(flag==0)return i;
	}
	return -1;
}
ll mp[maxn];
void mul(ll* a,ll* b ,ll* c){	
	for (int i = 0; i < z; i++) A[i] = a[i];
	for (int i = 0; i < z; i++) B[i] = b[i];
	for (int i = 0; i < z; i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
	NTT(A,1); NTT(B,1);
	for (int i = 0; i < z; i++) A[i] = 1ll * A[i] * B[i] % P;
	NTT(A,-1);
	for(int i=0;i<m-1;i++){
		c[i]=(A[i]+A[i+m-1])%P;
	}
}
ll f[maxn],g[maxn];
int main(){
	scanf("%lld %lld %lld %lld",&n,&m,&x,&s);
	ll yg=getroot(m);
	//printf("%lld\n",yg);
	for(int i=0;i<m-1;i++)mp[quickpow(yg,i,m)]=i;
	for(int i=1;i<=s;i++){
		int temp;
		scanf("%d",&temp);
		temp=temp%m;
		if(temp!=0)
		f[mp[temp]]++;
	}
	g[mp[1]]=1;
	L=0;
	for (z = 1; z <= 2*m; z <<= 1) L++;
	while(n!=0){
		if(n%2==1)mul(f,g,g);
		mul(f,f,f);
		n=n/2;
	}
	printf("%lld\n",g[mp[x]]);
}

P3321 [SDOI2015]序列统计

标签:code   turn   line   quic   ring   快速幂   red   lag   eve   

原文地址:https://www.cnblogs.com/League-of-cryer/p/14375669.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!