The solution of「CF603B Moodular Arithmetic」
\(\textup{CF603B Moodular Arithmetic}\)
\(\textup{Luogu}\) | \(\textup{Codeforces}\) | 洛谷文章 | 计数。
先说好,发现自己讲的很啰嗦,且思路借鉴楼上的题解。
\(\textup{Description}\)
给定 \(p,k\),求有多少种方案可以构造出序列 \(f_i\) 使得 \(\forall i, f_i < p\) 且 \(f_{k \cdot x \bmod p} = k \cdot f_{x \bmod p}\)。
\(\textup{Solution}\)
赛时想的太偏了呀,没有战胜呜呜呜。
我们发现,一个 \(f_i\) 会指向另一个,感觉到会连出一个环。
我们先考虑普通情况,可以这么推,对于 \(f_i\) 会连出的点有:
那么有 \(k ^ {y} \cdot i \equiv i \ (\bmod p)\),\(i \not\equiv 0\) 时,即 \(k ^ {y} \equiv 1 \ (\bmod p)\)。
我们再代入到题目给出的式子,发现:
这样就证明了一定可以化作一个环,且环首 \(f_i\) 我们知道后整个环就定下来了。
此时所有环长相等,都是是 \(y\),即满足 \(k ^ {y} \equiv 1 \ (\bmod p)\) 的最小正整数。
因为是第一次遇到,且 \(y,p\) 互质,这个是费马小定理的一个推论。
由于 \(f_i\) 有 \(p\) 种选法,故每个环有 \(p\) 种方案。
总共有 \(\frac{p - 1}{y}\) 个环,于是贡献为 \(p^{\large \frac{p - 1}{y}}\)。
接着思考一些特殊情况,比如 \(k = 0 / 1\) 的情况,因为 \(0\) 的时候就不可能形成环了,而 \(1\) 的时候就变成一堆自环了,所以需要特判断。这也是赛时给我们的部分分。
- \(k = 0\),只有 \(f_0\) 受影响,后面随便选,即 \(p ^ {p - 1}\);
- \(k = 1\),所有的都不受影响,贡献是 \(p ^ p\)。
最后,\(y\) 直接暴力去找就可以了,费马小定理保证了存在性,且最多跑 \(p - 1\),非常的好。
\(\textup{Code}\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const long long inf = 0x3f3f3f3f3f3f3f3f;
const int MOD = 1e9 + 7;
int P, K, ans;
int qpow( int a, int b ){
int ans = 1;
while( b ){
if( b & 1 ) ans = ( ans * a ) % MOD;
a = ( a * a ) % MOD;
b >>= 1;
}
return ans;
}
void slove(){
cin >> P >> K;
if( K == 0 ){
cout << qpow( P, P - 1 );
return;
}
if( K == 1 ){
cout << qpow( P, P );
return;
}
int cnt = 1, now = K;
while( now != 1 ){
now = ( now * K ) % P;
cnt ++;
}
cout << qpow( P, ( P - 1 ) / cnt );
}
signed main(){
// freopen( "hard.in", "r", stdin );
// freopen( "hard.out", "w", stdout );
ios::sync_with_stdio( false );
cin.tie( 0 );
cout.tie( 0 );
int T = 1;
// cin >> T;
while( T -- )
slove();
return 0;
}
\(\textup{Last}\)
如果您有所疑惑或我有所错漏,请您在评论区指出或找我,我会一定解答并且修改本题解。
如果您觉得本文写的还不错,那可以留个赞吗?
谢谢你看到这里~

浙公网安备 33010602011771号