zoukankan      html  css  js  c++  java
  • POJ1282 庆典的日期 置换群+模线性方程组[好题]

      题目链接: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 }
  • 相关阅读:
    【转】java正则表达式
    NDK学习笔记-使用现有so动态库
    NDK学习笔记-增量更新
    NDK学习笔记-增量更新
    NDK学习笔记-文件的拆分与合并
    NDK学习笔记-文件的拆分与合并
    NDK学习笔记-NDK开发流程
    NDK学习笔记-NDK开发流程
    NDK学习笔记-JNI的引用
    NDK学习笔记-JNI的引用
  • 原文地址:https://www.cnblogs.com/zhsl/p/3018380.html
Copyright © 2011-2022 走看看