POJ 2154 Color (Polya定理&欧拉函数)
2016-07-06 13:37
375 查看
Beads of N colors are connected together into a circular necklace of N beads (N<=1000000000). Your job is to calculate how many different kinds of the necklace can be produced. You should know that the necklace might not use up all the N colors, and the repetitions
that are produced by rotation around the center of the circular necklace are all neglected.
You only need to output the answer module a given number P.
Input
The first line of the input is an integer X (X <= 3500) representing the number of test cases. The following X lines each contains two numbers N and P (1 <= N <= 1000000000, 1 <= P <= 30000), representing a test case.
Output
For each test case, output one line containing the answer.
Sample Input
Sample Output
题意:用n种颜色涂环形的n个珠子,重复只考虑旋转,不考虑翻转,问能构成多少种?
题解:由Polya定理可以给出方案数:
,有很多i与n的gcd值相同,所以优化,把指数相同的一起算
令k=gcd(i,n),求有多少个i使之成立,枚举k,然后求i的个数:
显然n是k的倍数,令i=k*t,n=k*s;所以gcd(t,s)=1;求多少i变成了求多少t,再看范围,0<=i<n;所以0<=t<n/k;这里s=n/k;
问题就变成了求小于s与s互质的t有多少个答案就是eula(s)=eula(n/k),(欧拉函数)。
为了避免算1/n,把这个乘到和式里面,就是n的d-1次方。
#pragma comment(linker, "/STACK:10240000,10240000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<set>
#include<vector>
#include<map>
#include<stack>
#include<cmath>
#include<algorithm>
using namespace std;
const double R=0.5772156649015328606065120900;
const int N=31630+5;
//const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const double eps=1e-8;
const double pi=acos(-1.0);
typedef long long ll;
ll mod,tot=0;
bool vis
;
int pri
;
ll Pow(ll a,ll n)
{
a%=mod;
ll ans=1;
while(n)
{
if(n&1)
ans=ans*a%mod;
a=a*a%mod;
n>>=1;
}
return ans;
}
void init()
{
memset(vis,false,sizeof vis);
for(int i=2;i<N;i++)
if(!vis[i])
{
pri[tot++]=i;
for(int j=i;j<N;j+=i)
vis[j]=true;
}
}
int cnt[100];
ll a[100],all;
void resolve(ll n)//素因子分解
{
all=0;
memset(cnt,0,sizeof cnt);
for(int i=0;i<tot;i++)
if(n%pri[i]==0)
{
a[all++]=pri[i];
while(n%pri[i]==0) n/=pri[i],cnt[all-1]++;
}
if(n>1)
{
a[all++]=n;
cnt[all-1]++;
}
}
ll eula(ll n)
{
ll ans=n;
for(int i=0;i<all;i++)//枚举出来的数的因子肯定是n有的,直接用已有的因子那选
if(n%a[i]==0)
{
ans=ans/a[i]*(a[i]-1);
}
return ans;
}
ll dfs(int pos,ll mul,ll n)//dfs枚举所有因子,第pos个素因子,已经枚举的书为mul,原始的n
{
if(mul>n/mul) return 0;//大于sqrt(n)的已经算了
ll ans=0;
if(mul==n/mul)//注意完全平方数
{
ans=(ans+eula(mul)*Pow(n,n/mul-1))%mod;
return ans;
}
if(pos==all)
{
ans=(ans+eula(mul)*Pow(n,n/mul-1))%mod;//因子成对出现,sqrt(n)为界限
ans=(ans+eula(n/mul)*Pow(n,mul-1))%mod;
return ans;
}
ll tmp=1;
for(int i=0;i<=cnt[pos];i++)//枚举每个素因子选多少个,0就是不选
{
ans=(ans+dfs(pos+1,mul*tmp,n))%mod;
tmp*=a[pos];
}
return ans;
}
int main()
{
init();
int T_T;
scanf("%d",&T_T);
while(T_T--)
{
ll n;
scanf("%I64d%I64d",&n,&mod);
resolve(n);//分解n
printf("%I64d\n",dfs(0,1,n));
}
return 0;
}
/*
*/
that are produced by rotation around the center of the circular necklace are all neglected.
You only need to output the answer module a given number P.
Input
The first line of the input is an integer X (X <= 3500) representing the number of test cases. The following X lines each contains two numbers N and P (1 <= N <= 1000000000, 1 <= P <= 30000), representing a test case.
Output
For each test case, output one line containing the answer.
Sample Input
5 1 30000 2 30000 3 30000 4 30000 5 30000
Sample Output
1 3 11 70 629
题意:用n种颜色涂环形的n个珠子,重复只考虑旋转,不考虑翻转,问能构成多少种?
题解:由Polya定理可以给出方案数:
,有很多i与n的gcd值相同,所以优化,把指数相同的一起算
令k=gcd(i,n),求有多少个i使之成立,枚举k,然后求i的个数:
显然n是k的倍数,令i=k*t,n=k*s;所以gcd(t,s)=1;求多少i变成了求多少t,再看范围,0<=i<n;所以0<=t<n/k;这里s=n/k;
问题就变成了求小于s与s互质的t有多少个答案就是eula(s)=eula(n/k),(欧拉函数)。
为了避免算1/n,把这个乘到和式里面,就是n的d-1次方。
#pragma comment(linker, "/STACK:10240000,10240000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<set>
#include<vector>
#include<map>
#include<stack>
#include<cmath>
#include<algorithm>
using namespace std;
const double R=0.5772156649015328606065120900;
const int N=31630+5;
//const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const double eps=1e-8;
const double pi=acos(-1.0);
typedef long long ll;
ll mod,tot=0;
bool vis
;
int pri
;
ll Pow(ll a,ll n)
{
a%=mod;
ll ans=1;
while(n)
{
if(n&1)
ans=ans*a%mod;
a=a*a%mod;
n>>=1;
}
return ans;
}
void init()
{
memset(vis,false,sizeof vis);
for(int i=2;i<N;i++)
if(!vis[i])
{
pri[tot++]=i;
for(int j=i;j<N;j+=i)
vis[j]=true;
}
}
int cnt[100];
ll a[100],all;
void resolve(ll n)//素因子分解
{
all=0;
memset(cnt,0,sizeof cnt);
for(int i=0;i<tot;i++)
if(n%pri[i]==0)
{
a[all++]=pri[i];
while(n%pri[i]==0) n/=pri[i],cnt[all-1]++;
}
if(n>1)
{
a[all++]=n;
cnt[all-1]++;
}
}
ll eula(ll n)
{
ll ans=n;
for(int i=0;i<all;i++)//枚举出来的数的因子肯定是n有的,直接用已有的因子那选
if(n%a[i]==0)
{
ans=ans/a[i]*(a[i]-1);
}
return ans;
}
ll dfs(int pos,ll mul,ll n)//dfs枚举所有因子,第pos个素因子,已经枚举的书为mul,原始的n
{
if(mul>n/mul) return 0;//大于sqrt(n)的已经算了
ll ans=0;
if(mul==n/mul)//注意完全平方数
{
ans=(ans+eula(mul)*Pow(n,n/mul-1))%mod;
return ans;
}
if(pos==all)
{
ans=(ans+eula(mul)*Pow(n,n/mul-1))%mod;//因子成对出现,sqrt(n)为界限
ans=(ans+eula(n/mul)*Pow(n,mul-1))%mod;
return ans;
}
ll tmp=1;
for(int i=0;i<=cnt[pos];i++)//枚举每个素因子选多少个,0就是不选
{
ans=(ans+dfs(pos+1,mul*tmp,n))%mod;
tmp*=a[pos];
}
return ans;
}
int main()
{
init();
int T_T;
scanf("%d",&T_T);
while(T_T--)
{
ll n;
scanf("%I64d%I64d",&n,&mod);
resolve(n);//分解n
printf("%I64d\n",dfs(0,1,n));
}
return 0;
}
/*
*/
相关文章推荐
- 欧拉函数
- 线性筛法及扩展
- UVA11426GCD - Extreme (II)
- HDU 1695 GCD
- Farey Sequence(poj2478)
- 【欧拉函数】hdu 1286 找新朋友
- 欧拉函数
- 欧拉函数
- 欧拉函数
- poj_3910 GCD Determinant
- hdu1695 综合数论 欧拉函数 分解质因子 容斥原理 打印素数表 各种模板
- 欧拉函数
- LightOj 1298
- LightOj 1375(欧拉变形)
- HDU 1695(容斥+欧拉函数+素数分解)
- HDU 3501(欧拉函数)
- 同余式。。
- POJ 3696 : The Luckiest number - 欧拉函数,快速幂[数论好题]
- 数论 约数定理 约数和定理 欧拉定理
- poj 2478 Farey Sequence