POJ-1282 庆典的日期 置换群+模线性方程组[好题]
题目链接:http://poj.org/problem?id=1282
终于把这道题目给A了。
先来看看特殊情况:如果p=1的话,那就很容易做了,直接求每个循环节的长度,然后再求最小公倍数就行了。但是p!=1呢?如果依葫芦画瓢,通过n个置换去找循环节,然后再去求最小公倍数,那么难点就在找循环节上,很难处理,因此考虑换一种方法。
NOI2005论文,潘震皓的<置换群快速幂运算 研究与探讨>上有详细介绍,主要是对置换进行一个变化,然后去枚举答案。
1 //STATUS:C++_AC_0MS_452KB 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<string.h> 5 #include<math.h> 6 #include<iostream> 7 #include<string> 8 #include<algorithm> 9 #include<vector> 10 #include<queue> 11 #include<stack> 12 #include<map> 13 using namespace std; 14 #define LL __int64 15 #define pii pair<int,int> 16 #define Max(a,b) ((a)>(b)?(a):(b)) 17 #define Min(a,b) ((a)<(b)?(a):(b)) 18 #define mem(a,b) memset(a,b,sizeof(a)) 19 #define lson l,mid,rt<<1 20 #define rson mid+1,r,rt<<1|1 21 const int N=210,INF=0x3f3f3f3f,MOD=10000,STA=8000010; 22 const LL LNF=0x3f3f3f3f3f3f3f3f; 23 const double DNF=1e13; 24 25 LL a[N],m[N]; 26 int num[N][N],A[N][N],D[N][N],vis[N],vis2[N]; 27 int n,p; 28 29 void exgcd(LL a,LL b,LL& d,LL& x,LL& y) 30 { 31 if(!b){d=a;x=1;y=0;} 32 else {exgcd(b,a%b,d,y,x);y-=x*(a/b);} 33 } 34 35 LL Modline(int n) 36 { 37 LL d,x,y,A,M,Mod; 38 A=a[n-1],M=m[n-1]; 39 n--; 40 // m1*x-m2*y=a2-a1 41 while(n--){ 42 exgcd(M,m[n],d,x,y); 43 if((A-a[n])%d!=0){ 44 return -1; 45 } 46 Mod=m[n]/d; 47 x=(x*((a[n]-A)/d)%Mod+Mod)%Mod; 48 A+=M*x; 49 M=M/d*m[n]; 50 } 51 return A; 52 } 53 54 int find(int T[],int C[]) 55 { 56 int i,j,u,cnt=0,d,l,t,ok; 57 mem(vis,0); 58 for(i=0;i<n;i++){ 59 if(!vis[i]){ 60 l=-1,d=0;u=i; 61 while(!vis[u]){ 62 vis[u]=1; 63 mem(vis2,0); 64 for(t=ok=0,j=u;!vis2[j];t++,j=T[j]){ 65 vis2[j]=1; 66 if(j==C[u]){ok=1;break;} 67 } 68 if(l==-1)l=t; 69 if(!ok || l!=t)return 0; 70 u=C[u]; 71 d++; 72 } 73 a[cnt]=l,m[cnt++]=d; 74 } 75 } 76 return cnt; 77 } 78 79 int main() 80 { 81 // freopen("in.txt","r",stdin); 82 int i,j; 83 LL ans,x,t; 84 while(~scanf("%d%d",&n,&p)) 85 { 86 for(i=0;i<n;i++){ 87 for(j=0;j<p;j++){ 88 scanf("%d",&num[j][i]); 89 num[j][i]--; 90 } 91 } 92 for(i=0;i<n;i++)A[0][i]=num[0][i]; 93 for(i=1;i<p;i++){ 94 for(j=0;j<n;j++){ 95 A[i][j]=num[i][A[i-1][j]]; 96 } 97 } 98 for(i=0;i<p;i++){ 99 for(j=0;j<n;j++){ 100 D[i][A[i][j]]=j; 101 } 102 } 103 104 ans=LNF; 105 for(i=0;i<p;i++){ 106 if(t=find(A[p-1],D[i])){ 107 if((x=Modline(t))!=-1){ 108 ans=Min(ans,x*p+i+1); 109 if(ans>=1e9){ans=LNF;break;} 110 } 111 } 112 } 113 114 if(ans!=LNF)printf("%I64d\n",ans); 115 else printf("No one knows.\n"); 116 } 117 return 0; 118 }