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 }

 

你可能感兴趣的:(poj)