zoukankan      html  css  js  c++  java
  • poj 1282 庆典的日期 置换群

      根据题意,N个编号祭祀,N个房间,每个转盘上有P个数字,且每年保证每个房间有且仅有一个祭祀。

      可以转换成 P 个不同的 N元组置换。

      其中   为第i天祭祀位置, 为第 i 天转盘置换

      则 第i天 祭祀所在的房间为      (为什么是先D后T,因为置换的乘法是连接,先 )

      

      题目要求 经过 Y天,得到单位置换, 且总共P个不同的置换所以我们可以得到如下形式:

        (其中 e 为单位置换)

      假设 Y mod p  = k , 则可表示成如下形式:

      

      再转换一下:

       

      令 x = (y - k )/ p ,  , 得到

      上式转换成:

        

       对于  ,   我们通过预处理得出,然后枚举 K

       的 X 次幂,转换成  , N个元组相对应,我们可用通过置换模拟,求出每一个元组的 ( Ri, Ai ) 从而得到一个模同余方程组。

      求解方程组,得到X,然后得出Y。

    解题代码:

    View Code
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<iostream>
    using namespace std;
    
    typedef long long LL;
    const int N = 210;
    const LL inf = 1e9;
    int A[N][N], T[N][N], D[N][N], p, n;
    int r[N], a[N];// X = r[i] ( mod a[i] )
    
    bool find( int Q[], int key, int k, int &rr, int &aa )
    {
        int s = Q[k]; 
        rr = -1; aa = 1;
        if( k == key ) rr = 0;
        while( s != k )
        {    
            if( s == key ) rr = aa;
            aa++;
            s = Q[s];
        }
        return (rr == -1) ? false : true;
    }
    LL ExGcd( LL a, LL b, LL &x, LL &y )
    {
        if( b == 0 ) { x=1;y=0; return a;}
        LL r = ExGcd( b, a%b, x, y );
        LL t = x; x = y; y = t-a/b*y;
        return r;
    }
    LL ModLine( )
    {
        LL rr = r[0], aa = a[0];
        for(int i = 1; i < n; i++)
        {
            // r[i] - rr = aa*x + a[i]*y    
            LL x, y, C = r[i]-rr;
            LL d = ExGcd( aa, a[i], x, y );
            if( C%d != 0 ) return -1;
            LL Mod = a[i]/d;
            x = ((x*(C/d)%Mod)+Mod)%Mod;
            rr = rr + aa*x;
            aa = aa*(a[i]/d);
        }
        return rr;
    }
    int main()
    {
        while( scanf("%d%d", &n, &p) != EOF)
        {
            for(int i = 0; i < n; i++)
            {
                for(int j = 0; j < p; j++)
                {
                    scanf("%d", &A[j][i] );
                    A[j][i]--; // (0,1,2,...,n-1)
                }
            }
            for(int i = 0; i < n; i++)
                T[0][i] = A[0][i];
            for(int i = 1; i < p; i++)
            { // T[p-1]*T[p-2]*...*T[0]  置换乘法为连接,且左后右先
                for(int j = 0; j < n; j++)
                    T[i][j] = A[i][ T[i-1][j] ];
            }
            for(int i = 0; i < p; i++ )
            { // 求逆
                for(int j = 0; j < n; j++)
                    D[i][ T[i][j] ] = j;
            }
            LL res = inf;    
            // 枚举 Y % p = k, x = (Y-k)/p 
            for(int k = 0; k < p; k++)
            {// T[p-1]^x = D[k]
                bool flag = true;
                for(int i = 0; (i < n) && flag; i++)
                    if( !find( T[p-1], D[k][i], i, r[i], a[i] ) ) flag = false;
                if( !flag ) continue;    
                LL x = ModLine();
                if( ( x != -1 ) && ( x*p+k+1 < res ) )
                    res = x*p+k+1;    
            }
            if( res == inf ) puts("No one knows.");
            else    printf("%lld\n", res );
        }
        return 0;
    }
  • 相关阅读:
    321list,元组,range**数字是不可迭代的!
    320作业
    320基础数据类型初始
    319作业
    316作业
    319 Python基础之格式化输出、逻辑运算符、编码、in not in、while else、
    windows查看端口占用指令
    2016年学习计划
    刷算法的时候有没有必要自写测试用例?
    我们为什么不能只用O记号来谈论算法?
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/2844157.html
Copyright © 2011-2022 走看看