板子题都差点不会了
Description
小C有一个集合S,里面的元素都是小于M的非负整数。他用程序编写了一个数列生成器,可以生成一个长度为N的数
列,数列中的每个数都属于集合S。小C用这个生成器生成了许多这样的数列。但是小C有一个问题需要你的帮助:
给定整数x,求所有可以生成出的,且满足数列中所有数的乘积mod M的值等于x的不同的数列的有多少个。小C认为
,两个数列{Ai}和{Bi}不同,当且仅当至少存在一个整数i,满足Ai≠Bi。另外,小C认为这个问题的答案可能很大
,因此他只需要你帮助他求出答案mod 1004535809的值就可以了。
Input
一行,四个整数,N、M、x、|S|,其中|S|为集合S中元素个数。
第二行,|S|个整数,表示集合S中的所有元素。
1<=N<=10^9,3<=M<=8000,M为质数
0<=x<=M-1,输入数据保证集合S中元素不重复x∈[1,m-1]
集合中的数∈[0,m-1]
Output
一行,一个整数,表示你求出的种类数mod 1004535809的值。
题目分析
用$f_{i,j}$表示选了$i$个数乘积为$j$的方案数,不难得到式子$f_{2i,j}=sumlimits_{a*bequiv j(mod m)}f_{i,a} imes f_{i,b}$
对于乘法转加法,常见套路就是取对数。那么这里在模意义下,注意到原根$g$有很好的性质:$g^0,g^1,cdots ,g^{m-2}$可以取遍$[1cdots m-1]$,因此令$jequiv g^A(mod m)$,不妨用$A$代替$j$,以此类推。所以剩下的就是一个多项式快速幂的过程了,最终答案就是$f_x$的系数。
中途写错两个地方:为$[1cdots m-1]$内元素按$g^i$标号时,写成遍历$[0cdots m-1]$(这里整体下标减一。说到底还是对式子不熟练。);给$x$重标号时候,写成 if (x==tar&&!fl) tar = x, fl = 1; ……
1 #include<bits/stdc++.h> 2 #define MO 1004535809 3 const int maxn = 50035; 4 5 int T,n,m,tar,len,dt,inv3,invn,ort; 6 int f[maxn],g[maxn],cov[maxn],tmp1[maxn],tmp2[maxn]; 7 bool vis[maxn]; 8 9 int read() 10 { 11 char ch = getchar(); 12 int num = 0, fl = 1; 13 for (; !isdigit(ch); ch=getchar()) 14 if (ch=='-') fl = -1; 15 for (; isdigit(ch); ch=getchar()) 16 num = (num<<1)+(num<<3)+ch-48; 17 return num*fl; 18 } 19 int qmi(int a, int b, int p) 20 { 21 int ret = 1; 22 for (; b; b>>=1, a=1ll*a*a%p) 23 if (b&1) ret = 1ll*ret*a%p; 24 return ret; 25 } 26 int fndRoot() 27 { 28 int fac[10035], tot = 0, pos = m-1; 29 for (int i=2; i*i<=pos; i++) 30 if (pos%i==0){ 31 fac[++tot] = i; 32 while (pos%i==0) pos /= i; 33 } 34 if (pos!=1) fac[++tot] = pos; 35 pos = m-1; 36 for (int i=2; i<=pos; i++) 37 { 38 bool chk = true; 39 for (int j=1; j<=tot&&chk; j++) 40 if (qmi(i, pos/fac[j], m)==1) chk = false; 41 if (chk) return i; 42 } 43 return -1; 44 } 45 void NTT(int *a, int opt) 46 { 47 for (int i=0; i<len; i++) 48 if (i < cov[i]) std::swap(a[i], a[cov[i]]); 49 for (int i=1; i<len; i<<=1) 50 { 51 int Wn = qmi(3, (MO-1)/(i<<1), MO); 52 if (opt==-1) Wn = qmi(inv3, (MO-1)/(i<<1), MO); 53 for (int j=0, p=i<<1; j<len; j+=p) 54 { 55 int w = 1; 56 for (int k=0; k<i; k++, w=1ll*w*Wn%MO) 57 { 58 int valx = a[j+k], valy = 1ll*w*a[i+j+k]%MO; 59 a[j+k] = (valx+valy)%MO, a[i+j+k] = (valx-valy+MO)%MO; 60 } 61 } 62 } 63 if (opt==-1) for (int i=0; i<len; i++) a[i] = 1ll*a[i]*invn%MO; 64 } 65 void mult(int *a, int *b) 66 { 67 for (int i=0; i<len; i++) tmp1[i] = a[i], tmp2[i] = b[i]; 68 NTT(tmp1, 1), NTT(tmp2, 1); 69 for (int i=0; i<len; i++) tmp1[i] = 1ll*tmp1[i]*tmp2[i]%MO; 70 NTT(tmp1, -1); 71 for (int i=0; i<m-1; i++) a[i] = (tmp1[i]+tmp1[i+m-1])%MO; 72 } 73 int main() 74 { 75 T = read(), m = read(), tar = read(), n = read(); 76 inv3 = qmi(3, MO-2, MO), ort = fndRoot(); 77 for (int i=1; i<=n; i++) vis[read()] = true; 78 for (int i=0, x=1, fl=0; i<m-1; i++, x=1ll*x*ort%m) 79 { 80 if (vis[x]) g[i] = 1; 81 if (x==tar&&!fl) tar = i, fl = 1; 82 } 83 for (len=1; len<=(m-1)<<1; len<<=1) ++dt; 84 for (int i=0; i<len; i++) 85 cov[i] = (cov[i>>1]>>1)|((i&1)<<(dt-1)); 86 f[0] = 1, invn = qmi(len, MO-2, MO); 87 for (; T; T>>=1, mult(g, g)) 88 if (T&1) mult(f, g); 89 printf("%d ",f[tar]); 90 return 0; 91 }
END