跳转至

群论

置换群

置换:给定一个序列a,将a重新排列后一一映射即为置换

循环置换:将序列a整体向右平移1位后一一映射。

任意一个置换都可以拆分成若干个循环置换的乘积(乘积:设两个置换映射为f(x),g(x),这其乘积为g(f(x)))

其实是废话,因为循环置换太特殊啦!

置换群:对于一个长度为n的序列a,其所有置换有n!种,选择其中若干种即为一个置换群。

Polya定理

Burnside引理:每个置换的**不动点**个数的平均值就是不同方案数。

Polya定理:假设有一个置换可以拆成k个循环,每个循环有c种选法,那么这个置换的不动点的个数就是\(c^k\)

std

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define ps second
#define pf first


#define rd read()
inline int read()
{
    int xx=0,ff=1;
    char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') ff=-1;c=getchar();}
    while(c>='0'&&c<='9') xx=xx*10+(c-'0'),c=getchar();
    return xx*ff;
}
inline void write(int out)
{
    if(out<0) putchar('-'),out=-out;
    if(out>9) write(out/10);
    putchar(out%10+'0');
}


const int N=2e5+5;
const int M=5e5+5;
const int INF=1e9+5;
const int MOD=1e9+7;
bool f1;
int m,k,n,qzh;

int q;
int T,mn=INF,ans;

int ksm(int a,int b){ 
    int res=1;
    while(b){
        if(b&1)res=(res*a)%MOD;
        a=(a*a)%MOD;
        b>>= 1;
    }
    return res;
}

int euler(int n) { //欧拉函数
    int res=1;
    for(int i=2; i*i<=n; i++)
        if(n%i==0) {
            n/=i,res=res*(i-1);
            while(n%i==0) n/=i,res=res*i;
        }
    if(n>1) res=res*(n-1);
    return res;
}

int polya(int m,int n) {
    int tot=0;
    for(int i=1; i*i<=n; i++) {
        if(n%i) continue;
        tot+=euler(i)*ksm(m,n/i-1);
        if(i*i!=n) tot+=euler(n/i)*ksm(m,i-1);
    }
    return tot%MOD;
}

signed main(){
    int t=rd;
    while(t--){
        int n=rd;
        cout<<polya(n,n)<<endl;
    }
}