[loj3330]猜数游戏

如果两个数$a_{x}$和$a_{y}$,$\exists 0<i,a_{x}^{i}\equiv a_{y}(mod\ p^{k})$,就建一条$x$到$y$的有向边,再对这张图强连通分量缩点,记$s_{i}$表示第$i$个点的大小,$f_{i}$表示能到达$i$的点(初始)数量,则答案为$\sum_{i=1}^{scc}\frac{2^{s_{i}}-1}{2^{s_{i}+f_{i}}}$(对每一个点分别统计贡献)
问题就变为如何判定$\exists i,x^{i}\equiv y(mod\ p^{k})$,分为$p\mid x$和$p\nmid x$两类
对于$x\mid p$和$y\nmid p$,$x^{i}\equiv y(mod\ p^{k})$的必要条件为$x^{i}\equiv y(mod\ p)$,而$x^{i}\equiv 0\ne y(mod\ p)$(交换$x$和$y$也同理可以证明),因此两类之间没有关系
对于$x\mid p$和$y\mid p$,必然有$\forall k\le i,x^{i}\equiv 0(mod\ p^{k})$,暴力枚举$i$即可,时间复杂度$o(n\log p)$
对于$x\nmid p$和$y\nmid p$,如果求出$且ord(x)=\min_{i>0且x^{i}\equiv 1(mod\ p^{k})}i$,那么$x^{i}\equiv y(mod\ p^{k})$当且仅当$ord(y)\mid ord(x)$
用BSGS求$ord(x)$复杂度及常数较大,考虑$ord(x)\mid \varphi(p)$,枚举$\varphi(p)$的质因子并判断能否消除,复杂度为$o(n\log^{2}p)$
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 5005
 4 #define mod 998244353
 5 map<int,int>mat;
 6 vector<int>v,v1[N],v2[N],v3[N];
 7 int n,m,P,p,k,ans,a[N],ord[N],vis[N],dfn[N],sz[N],bl[N],dp[N];
 8 int ksm(int n,int m,int p){
 9     if (!m)return 1;
10     int s=ksm(n,m>>1,p);
11     s=1LL*s*s%p;
12     if (m&1)s=1LL*s*n%p;
13     return s; 
14 }
15 int bsgs(int k){
16     int ans=1;
17     for(int i=0;i<v.size();i++)ans=ans*v[i];
18     for(int i=0;i<v.size();i++)
19         if (ksm(k,ans/v[i],P)==1)ans/=v[i];
20     return ans;
21 }
22 void add(int x,int y){
23     v1[x].push_back(y);
24     v2[y].push_back(x);
25 }
26 void dfs1(int k){
27     if (vis[k])return;
28     vis[k]=1;
29     for(int i=0;i<v1[k].size();i++)dfs1(v1[k][i]);
30     dfn[++dfn[0]]=k;
31 }
32 void dfs2(int k){
33     if (bl[k]){
34         if (bl[k]!=m)v3[m].push_back(bl[k]);
35         return;
36     }
37     sz[m]++;
38     bl[k]=m;
39     for(int i=0;i<v2[k].size();i++)dfs2(v2[k][i]);
40 }
41 void dfs3(int k,int x){
42     if (vis[k])return;
43     vis[k]=1;
44     dp[x]+=sz[k];
45     for(int i=0;i<v3[k].size();i++)dfs3(v3[k][i],x);
46 }
47 void init(){
48     p=P;
49     for(int i=3;i*i<=P;i++)
50         if (P%i==0){
51             p=i;
52             break;
53         }
54     for(int i=P;i>1;i/=p)k++;
55     int j=P/p*(p-1);
56     for(int i=2;i*i<=j;i++)
57         while (j%i==0){
58             j/=i;
59             v.push_back(i);
60         }
61     if (j>1)v.push_back(j);
62 }
63 void Kosaraju(){
64     memset(vis,0,sizeof(vis));
65     for(int i=1;i<=n;i++)dfs1(i);
66     for(int i=n;i;i--)
67         if (!bl[dfn[i]]){
68             m++;
69             dfs2(dfn[i]);
70         }
71 }
72 int main(){
73     scanf("%d%d",&n,&P);
74     init();
75     for(int i=1;i<=n;i++){
76         scanf("%d",&a[i]);
77         mat[a[i]]=i;
78     }
79     for(int i=1;i<=n;i++)
80         if (a[i]%p)ord[i]=bsgs(a[i]);
81         else{
82             for(int j=1,t=a[i];t>0;j++,t=1LL*t*a[i]%P)
83                 if ((mat[t])&&(mat[t]!=i))add(i,mat[t]);
84         }
85     for(int i=1;i<=n;i++)
86         for(int j=1;j<=n;j++)
87             if ((i!=j)&&(ord[i])&&(ord[j])&&(ord[i]%ord[j]==0))add(i,j);
88     Kosaraju();
89     for(int i=1;i<=m;i++){
90         memset(vis,0,sizeof(vis));
91         dfs3(i,i);
92     }
93     for(int i=1;i<=n;i++)ans=(ans+(ksm(2,sz[i],mod)-1LL)*ksm(2,n-dp[i],mod))%mod;
94     printf("%d",ans);
95     return 0;
96 }
View Code

 

posted @ 2020-08-14 15:49  PYWBKTDA  阅读(161)  评论(0编辑  收藏  举报