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. 1≤N≤1000000000(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(n−1)+g(n−2),g(1)=1,g(2)=3
我们递推来求试试:设f(n)为染色结尾的所有可能,设h(n)为不染色结尾的所有可能(且全部为链状而不是环)g(n)为环状时的肯能数,那么有:
显然可以吧f(n)替代有:
因为:
所以g(n)也是斐波那契数列
最后根据burnside引理有:
但是线性枚举依然超时的,所以经典套路去枚举gcd,引入欧拉函数ϕ:
至此理论部分完成(默认你理解相关群论知识)
#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;
}