1. 程式人生 > 實用技巧 >[loj3330]猜數遊戲

[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