ICPC2017青岛 - Floppy Cube(Pólya 定理)
题解
Pólya定理用于计算在置换下的所有本质不同的方案数。
可以发现,操作产生的所有置换都可以通过横向旋转90度,纵向旋转180度,左侧一列转动180度这三个置换产生。只需bfs,通过这三个置换搜索出所有可能的置换,假设这个置换的集合是\(G\),颜色数为\(c\),答案即为
\[\frac{1}{|G|}\sum\limits_{g\in G}{c^{f(g)}}
\]
其中\(f(g)\)代表置换\(g\)能拆分成的不相交的循环置换的数量。
用于模数和颜色数都比较大,值域\(10^9\)。模数\(P\)不确定的情况下,要取模后除去一个数\(k\),无法确保有逆元。假如最终结果(假设为\(n\))可以被\(k\)整除,那么有
\[(n\mod Pk)= (k\frac{n}{k} \mod Pk) \\
k(\frac{n}{k} \mod P) = (n \mod Pk) \\
(\frac{n}{k} \mod P)=\frac{(n \mod Pk)}{k}
\]
因此为了除去\(|G|\),只需对结果模\(P|G|\),最后除去\(|G|\)即可。
#include <bits/stdc++.h>
#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const int N = 3e5 + 10;
const double eps = 1e-5;
vector<int> g1 = {6, 3, 0, 7, 4, 1, 8, 5, 2, 15, 12, 9, 16, 13, 10, 17, 14, 11, 21, 22, 23, 24, 25, 26, 27, 28, 29, 18, 19, 20};
vector<int> g2 = {15, 16, 17, 12, 13, 14, 9, 10, 11, 6, 7, 8, 3, 4, 5, 0, 1, 2, 26, 25, 24, 23, 22, 21, 20, 19, 18, 29, 28, 27};
vector<int> g3 = {0, 1, 17, 3, 4, 14, 6, 7, 11, 9, 10, 8, 12, 13, 5, 15, 16, 2, 18, 19, 24, 23, 22, 21, 20, 25, 26, 27, 28, 29};
bool chk(vector<int> &g) {
vector<int> vis(30, 0);
for(int i = 0; i < g.size(); i++) vis[g[i]] = 1;
for(int i = 0; i < 30; i++) if(!vis[i]) return false;
return true;
}
set<vector<int> > ans;
int cnt[100];
int cal(const vector<int>& pi) {
vector<int> vis(30, 0);
int res = 0;
for(int i = 0; i < pi.size(); i++) {
if(vis[i]) continue;
res++;
int cur = pi[i];
while(!vis[cur]) {
vis[cur] = 1;
cur = pi[cur];
}
}
return res;
}
vector<int> change(const vector<int>& d, const vector<int> &g) {
vector<int> nt(30);
for(int i = 0; i < 30; i++) {
nt[i] = d[g[i]];
}
return nt;
}
void solve(vector<int> s) {
queue<vector<int>> q;
q.push(s);
ans.insert(s);
while(!q.empty()) {
auto cur = q.front();
q.pop();
vector<int> nt;
nt = change(cur, g1);
if(!ans.count(nt)) {ans.insert(nt); q.push(nt);}
nt = change(cur, g2);
if(!ans.count(nt)) {ans.insert(nt); q.push(nt);}
nt = change(cur, g3);
if(!ans.count(nt)) {ans.insert(nt); q.push(nt);}
}
for(auto p : ans) {
cnt[cal(p)]++;
}
}
ll mpw(ll x, int p) {
ll res = 1;
while(p--) {
res *= x;
}
return res;
}
ll qmul(ll x, ll y, ll m) {
return (__int128)x * y % m;
}
inline ll qpow(ll a, ll b, ll m) {
ll res = 1;
while(b) {
if(b & 1) res = qmul(res, a, m);
a = qmul(a, a, m);
b = b >> 1;
}
return res;
}
int main() {
IOS;
vector<int> s;
for(int i = 0; i < 30; i++) s.push_back(i);
solve(s);
ll tot = ans.size();
int t;
cin >> t;
while(t--) {
ll n, p;
cin >> n >> p;
p *= tot;
ll ans = 0;
for(int i = 1; i <= 30; i++) {
ans = (ans + cnt[i] * qpow(n, i, p) % p) % p;
}
assert(ans % tot == 0);
cout << ans / tot << endl;
}
}