根据题意,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。
解题代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }