ICPC2017青岛 - Floppy Cube(Pólya 定理)

Floppy Cube

题解

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;
    }
}
posted @ 2021-10-31 21:26  limil  阅读(40)  评论(0编辑  收藏  举报