【NOIP模拟赛】随

题目链接:

  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\n",ans);
83 }

 

posted @ 2017-08-29 16:13  Troywar  阅读(192)  评论(0编辑  收藏  举报