2017 青岛 E Floppy Cube

题目链接
https://nanti.jisuanke.com/t/18515

题面:
The Floppy Cube is essentially a 1 × 3 × 3 Rubik’s Cube. It is made up of 9 identical cubic pieces arranged into a 1 × 3 × 3 cuboid. The puzzle consists of 4 corner pieces, 4 edge pieces and 1 centre piece. Each corner piece has four colours each, each edge piece has three colours each, while the centre piece has two colours (on the opposite faces). The puzzle can be thought of as twisting around its edge pieces. Each twist causes one edge piece to rotate 180 degrees in place, and the two adjacent corner pieces to swap position (while also being rotated). Of course, rotating or flipping the entire Floppy Cube are available moves as well. The purpose of the puzzle is to restore it to the state of having one colour per face.

Suppose that we wish to apply new colour stickers to a Floppy Cube in a colouring which is not necessary to be a standard colouring. Specifically, we have n different colours available (with an unlimited supply of stickers of each colour), and we place one sticker on each of the 30 faces in any arrangement that we please. We are not required to use all the colours, and if desired the same colour may appear in more than one face of a single cubic piece.

We say that two such colouring c1 and c2 are essentially distinct if a cube coloured according to c1 cannot be made to match a cube coloured according to c2 by performing mechanically possible Floppy Cube moves. How many essentially distinct colourings are there with n different colours available?

Input
The input has several test cases, and the first line contains an integer T (1 ≤ T ≤ 22222) which is the total number of test cases. For each case, a line contains two integers n and P where 1 ≤ n, P ≤ 111111111.

Output
For each case, calculate the number of distinct colouring with n different colours available, and output the remainder when it divided by P.

sol:

1. polya p o l y a 裸题 。因为这个变换看起来没有什么性质,无法手推,考虑把所有的置换群找出来,这个用bfs搜或者dfs搜都可以。

2.实际上所有的置换群都可以用三个元操作组合完成,分别是
1) 将最右边的棱进行翻转
2) 顺时针旋转
3) 整体前后翻转

考虑将每个面按如下方法进行标号:
正面和反面:

这里写图片描述

左面和右边:
这里写图片描述

上面和下面:
这里写图片描述

然后就可以大力爆搜啦,直接用 set<vector<int>> s e t < v e c t o r < i n t >> 暴力存好像也没啥问题。

3.找出循环节之后应用 polya p o l y a 定理,设 f(G) f ( G ) 为置换G的循环节个数,颜色种数为c则有
ans=1nni=1cf(Gi) a n s = 1 n ∑ i = 1 n c f ( G i )

4.注意几个细节
1)p不一定为质数,所以不一定有逆元,可以通过对 (nP) ( n ∗ P ) 取模再 除以 n n 。这可能会超过1e11,所以需要大数或者__128.

code:

#include<bits/stdc++.h>

using namespace std;

typedef __int128 lll;
typedef long long ll;
const int maxn = 1e5 + 10;

#define pb push_back

//变换1
int a1[31] = {0,  1,  2, 18,  4,  5, 15,  7,  8, 12, 10,
                 11,  9, 13, 14,  6, 16, 17,  3, 19, 20,
                 22, 21, 23, 24, 25, 26, 27, 30, 29, 28};

//变换2
int a2[31] = {0,  7,  4,  1,  8,  5,  2,  9,  6,  3, 16,
                 13, 10, 17, 14, 11, 18, 15, 12, 28, 29,
                 30, 25, 26, 27, 19, 20, 21, 22, 23, 24};

//变换3
int a3[31] = {0, 16, 17, 18, 13, 14, 15, 10, 11, 12,  7,
                  8,  9,  4,  5,  6,  1,  2,  3, 24, 23,
                 22, 21, 20, 19, 27, 26, 25, 30, 29, 28};

set<vector<int> > sol;
vector<int> turn[4];

vector<int> Mul(vector<int>& a,vector<int>& b){
    vector<int> ret;
    ret.resize(31);
    for(int i = 1;i <= 30;i++) ret[i] = b[a[i]];
    return ret;
}

void dfs(vector<int> x){
    for(int i = 1;i<= 3;i++){
        vector<int> ret = Mul(x,turn[i]);
        if(sol.count(ret) == 0){
            sol.insert(ret);
            dfs(ret);
        }
    }
}



unordered_map<int,int> mp;
bool vis[32];

void Cal(){
    mp.clear();
    for(vector<int> x : sol){
        memset(vis,false,sizeof(vis));
        int cnt = 0;
        for(int i = 1;i<=30;i++){
            if(!vis[i]){
                cnt ++;
                int ret = i;
                vis[ret] = true;
                while(!vis[x[ret]]){
                    ret = x[ret];
                    vis[ret] = true;
                }
            }
        }
        mp[cnt]++;
    }
}

lll qpow(lll a,ll b,lll p){
    lll ret = 1;
    while(b){
        if(b&1) ret = ret * a % p;
        a = a*a % p;
        b >>= 1;
    }
    return ret;
}

#define fi first
#define se second

void init(){
    for(int i = 0;i<= 30;i++){
        turn[1].push_back(a1[i]);
        turn[2].push_back(a2[i]);
        turn[3].push_back(a3[i]);
    }
    vector<int> ret;
    ret.resize(31);
    for(int i = 0;i<=30;i++) ret[i] = i;
    sol.insert(ret);
    dfs(ret);
    Cal();
}

int main(){
    init();
    int T;
    scanf("%d",&T);
    ll sz = sol.size();
    // cout<<sz<<endl;
    while(T--){
        ll n,p;
        scanf("%lld%lld",&n,&p);
        lll ans = 0;
        for(auto x : mp){
            lll mod = p;
            mod *= sz;
            lll ret = qpow(n,x.fi,mod);
            ret = ret * x.se % mod;
            ans += ret;
            ans %= mod;
        }
        ans /= sz;
        ll out = ans;
        printf("%lld\n",out);
    }
    return 0;
}

顺便放下组队赛的polya题,出题人卡空间卡得有点丧心病狂啊,bfs搜索加Hash去重

题目链接:https://scut.online/p/296

code:

#include<bits/stdc++.h>

using namespace std;

typedef __int128 lll;
typedef vector<char> vi;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5 + 10;
const int PP = 19260817;

#define fi first
#define se second

int n,m;

vi Turn[10];
unordered_set<ull> sol;
unordered_map<int,int> ms;

vi Mul(vi& a,vi& b){
    vi ret;
    ret.resize(n+1);
    for(int i = 1;i<=n;i++) ret[i] = b[a[i]];
    return ret;
}

ull Hash(vi& x){
    ull ret = 0;
    for(int i = 1;i<x.size();i++){
        ret = ret * PP + x[i];
    }
    return ret;
}

bool vis[10];

void Cal(vi& x){
        memset(vis,false,sizeof(vis));
        int cnt = 0;
        for(int i = 1;i<=n;i++){
            if(!vis[i]){
                cnt++;
                int ret = i;
                vis[ret] = 1;
                while(!vis[x[ret]]){
                    ret = x[ret];
                    vis[ret] = 1;
                }
            }
        }
        ms[cnt]++;
}

void BFS(vi x){
    queue<vi > Q;
    int maxx = 0;
    Q.push(x);
    sol.insert(Hash(x));
    while(!Q.empty()){
        vi u = Q.front();Q.pop();
        maxx = max(maxx,(int)Q.size());
        Cal(u);
        for(int i = 1;i<=m;i++){
            vi ret = Mul(u,Turn[i]);
            ull tmp = Hash(ret);
            if(sol.count(tmp) == 0){
                sol.insert(tmp);
                Q.push(ret);
            }
        }
    }
}

inline void Mul(lll& a,lll b,lll p){
    a *= b;
    if(a>=p) a %= p;
}

inline void Add(lll& a,lll b,lll p){
    a += b;
    if(a>=p) a-= p;
}

lll qpow(lll a,ll b,lll p){
    lll ret = 1;
    while(b){
        if(b&1) Mul(ret,a,p);
        Mul(a,a,p);
        b >>= 1;
    }
    return ret;
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int C,P;
        scanf("%d%d%d%d",&n,&m,&C,&P);
        for(int o = 1; o <= m; o++){
            int op;
            scanf("%d",&op);
            vi& ret = Turn[o];
            ret.resize(n+1); 
            for(int i = 0;i<=n;i++) ret[i] = i;
            if(op == 1){
                int l,r;
                scanf("%d%d",&l,&r);
                for(int i = 0;l+i<r-i;i++){
                    swap(ret[l+i],ret[r-i]);
                }
            }
            else {
                int L1,L2,t;
                scanf("%d%d%d",&L1,&L2,&t);
                for(int i = 0;i<t;i++){
                    swap(ret[L1+i],ret[L2+i]);
                }
            }
        }
        ms.clear();
        sol.clear();
        vi ret(n+1);
        for(int i = 0;i<=n;i++) ret[i] = i;
        BFS(ret);
        ll sz = sol.size();
        lll mod = P;
        mod *= sz;
        lll ans = 0;
        for(auto x : ms){
            lll ret = qpow(C,x.fi,mod);
            Mul(ret,x.se,mod);
            Add(ans,ret,mod);
        }
        ans /= sz;
        ll out = ans;
        printf("%lld\n",out);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值