Different Circle Permutation HDU - 5868(burnside引理+递推+矩阵快速幂+欧拉函数)

You may not know this but it’s a fact that Xinghai Square is Asia’s largest city square. It is located in Dalian and, of course, a landmark of the city. It’s an ideal place for outing any time of the year. And now:

There are NN children from a nearby primary school flying kites with a teacher. When they have a rest at noon, part of them (maybe none) sit around the circle flower beds. The angle between any two of them relative to the center of the circle is always a multiple of 2π/N but always not 2π/N .

Now, the teacher raises a question: How many different ways there are to arrange students sitting around the flower beds according to the rule stated above. To simplify the problem, every student is seen as the same. And to make the answer looks not so great, the teacher adds another specification: two ways are considered the same if they coincide after rotating.
Input
There are T tests (T≤50). Each test contains one integer N. 1N1000000000(109) . Process till the end of input.
Output
For each test, output the answer mod 1000000007(109+7) in one line.
Sample Input
4
7
10
Sample Output
3
5
15

这题看了以后就知到考的polya技术,但是是带有限制的,这里带有限制的题,我做的不多,得用burnside引理,具体参见组合数学最后一章。
题目相当于一个染色问题,但是相邻两个不能同时染色,而且旋转同构
先看旋转不同构的情况有多少种,设为 g(n) ,其实正规解法是要去递推来求,但是推导能力得很强,找规律也不是不可以的,我们可以发现 g(n)=g(n1)+g(n2)g(1)=1g(2)=3
我们递推来求试试:设 f(n) 为染色结尾的所有可能,设 h(n) 为不染色结尾的所有可能(且全部为链状而不是环) g(n) 为环状时的肯能数,那么有:

h(n)=f(n1)+h(n1)
f(n)=h(n1)

显然可以吧 f(n) 替代有:
h(n)=h(n2)+h(n1)
,现在把它连成环,自然也是合法的,现在考虑 f(n) ,这个是不能直接连成环的,因为必须考虑它的头有没有染色,那么我们只要从第2个开始考虑,第一个就默认为没有染色了,所有有:
g(n)=h(n)+f(n1)
f(n1) 替代有:
g(n)=h(n)+h(n2)

因为:
g(n1)+g(n2)=h(n1)+f(n3)+h(n2)+f(n4)=h(n)+h(n2)=g(n)

所以 g(n) 也是斐波那契数列

最后根据burnside引理有:

ans=1ni=1ng(gcd(i,n))

但是线性枚举依然超时的,所以经典套路去枚举gcd,引入欧拉函数 ϕ
ans=1nd|nng(d)ϕ(nd)

至此理论部分完成(默认你理解相关群论知识)

#include<iostream>
#include<cstdio>
#include<cstring>
#define mod 1000000007
using namespace std;
typedef long long ll;
int phi(int x)//欧拉函数
{
    int  ans=x;
    for(int i=2;i*i<=x;i++)
    {
        if(x%i==0)
        {
            ans-=ans/i;
            while(x%i==0)
                x/=i;
        }
        if(x==1)
        break;
    }
    if(x!=1)
        ans-=ans/x;
    return ans;
}
struct M//矩阵求斐波那契数列
{
    ll a[2][2];
    void init()
    {
        memset(a,0,sizeof(a));
    }
    void unit()
    {
        init();
        a[0][0]=1;
        a[1][1]=1;
    }
    M muil(M x)
    {
        M ans;
        for(int i=0;i<2;i++)
        {
            for(int j=0;j<2;j++)
            {
                ans.a[i][j]=0;
                ans.a[i][j]=(a[i][0]*x.a[0][j]%mod+a[i][1]*x.a[1][j])%mod;
            }
        }
        return ans;
    }
};
ll f(int x)//矩阵快速幂
{
    if(x==1)
    return 1;
    if(x==2)
    return 3;
    x-=2;
    M ans;
    ans.unit();
    M u;
    u.a[0][0]=1;
    u.a[0][1]=1;
    u.a[1][0]=1;
    u.a[1][1]=0;
    while(x)
    {
        if(x&1)
            ans=ans.muil(u);
        u=u.muil(u);
        x>>=1;
    }
    return (ans.a[0][0]*3+ans.a[0][1])%mod;
}
ll P(ll a,ll b)
{
    ll ans=1;
    ll temp=a;
    while(b)
    {
        if(b&1)
            ans=ans*temp%mod;
        temp=temp*temp%mod;
        b>>=1;
    }
    return ans;
}
ll getInv(int n)//求逆元,因为有除法取模
{
    return P(n,mod-2);
}
ll solve(int n)
{
    ll ans=0;
    int L;
    for(L=1;L*L<n;L++)
    {
        if(n%L==0)
        {
            ans=(ans+phi(n/L)*f(L))%mod;
            ans=(ans+phi(L)*f(n/L))%mod;//折半枚举
        }
    }
    if(L*L==n)
        ans=(ans+phi(L)*f(L))%mod;  
    ans=ans*getInv(n)%mod;
    return ans;
}
int main()
{
    int n;
    while(scanf("%d",&n)==1)
    {
        if(n==1)//1的时候特判一下
            printf("2\n");
        else
            printf("%lld\n",solve(n));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值