题目链接:
172.18.111.252:800/problem.php?cid=1001&pid=0
题解:
膜达神……(NOIP考这个就等爆零吧……)
显然我们得到一个结论:$ans=sum_{i=0}^{mod-1}i*f_{i}$,其中$f_{i}$表示结果为i的概率。
那么问题就是求$f_{i}$。
最初我们可以想到用暴力枚举所有状态,显然超时,怎么优化,矩阵dp。可以开一个$n^{2}$的矩阵来递推。但这样时间$n^{3}log(n)$还是过不去。深入探讨,我们发现,给的mod是很小的,也就意味着可以把许多$a_{i}$合并概率,同时我们发现(题目下面提示),这原根似乎没用到。(⊙v⊙)嗯。
我们设$g$为原根,那么对于所有的$a_{i}$我们都可以用$g^{x}$来表示,然后结合欧拉定理,我们就可以到到一个新的递推式:$f_{i,j}=sum_{x=0}^{mod-2}f_{i-1,x}*f_{i-1,j-x}$其中$f_{i,j}$表示i次选取后,结果为原根的j次幂的概率,$j-x$为其在mod-1意义下的剩余系。这个式子显然可以矩阵优化,同时我们发现这个矩阵是一个循环矩阵,然后我们就可以在$O(mod^{2}log(m))$的时间内求出答案。
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 const int mod=int(1e9)+7,N=1010; 5 inline int read(){ 6 int s=0;char ch=getchar(); 7 while(ch<'0'||ch>'9') ch=getchar(); 8 while(ch>='0'&&ch<='9') s=s*10+(ch^48),ch=getchar(); 9 return s; 10 } 11 int n,m,P,P2; 12 int yuan(){ 13 for(int i=1;i<P;i++){ 14 int x=1; 15 bool flag=true; 16 for(int j=1;j<P2;j++){ 17 x=x*i%P; 18 if(x==1){ 19 flag=false;break; 20 } 21 } 22 if(flag) return i; 23 } 24 } 25 inline int powmod(int a,int b){ 26 int ans=1; 27 while(b){ 28 if(b&1) ans=1LL*ans*a%mod; 29 b>>=1; 30 a=1LL*a*a%mod; 31 }return ans; 32 } 33 struct Matrix{ 34 int a[N]; 35 Matrix (){memset(a,0,sizeof(a));} 36 }now,a; 37 Matrix t; 38 int pi[N],logs[N]; 39 int cnt[N]; 40 int main(){ 41 n=read(),m=read(),P=read();P2=P-1; 42 int rt=yuan(); 43 44 int x=1; 45 logs[1]=0; 46 pi[0]=1; 47 for(int i=1;i<P2;i++){ 48 x=1LL*x*rt%P; 49 pi[i]=x; 50 logs[x]=i; 51 } 52 for(int i=1;i<=n;i++) 53 cnt[logs[read()]]++; 54 55 int re=powmod(n,mod-2); 56 for(int i=0;i<P2;i++) 57 cnt[i]=1LL*cnt[i]*re%mod; 58 now.a[0]=1; 59 for(int i=0;i<P2;i++) 60 a.a[i]=cnt[(P2-i)%P2]; 61 while(m){ 62 if(m&1) { 63 for(int i=0;i<P2;i++){ 64 t.a[i]=0; 65 for(int j=0;j<P2;j++) 66 t.a[i]=(1LL*t.a[i]+1LL*now.a[j]*a.a[(i-j+P2)%P2])%mod; 67 } 68 now=t; 69 } 70 m>>=1; 71 for(int i=0;i<P2;i++){ 72 t.a[i]=0; 73 for(int j=0;j<P2;j++) 74 t.a[i]=(1LL*t.a[i]+1LL*a.a[j]*a.a[(i-j+P2)%P2])%mod; 75 } 76 a=t; 77 } 78 int ans=0; 79 for(int i=0;i<P2;i++){ 80 ans=(ans*1LL+pi[i]*1LL*now.a[(P2-i)%P2]%mod)%mod; 81 } 82 printf("%d ",ans); 83 }