題目鏈接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=52936
題意:要求找滿足條件的a,b有多少種,條件是:gcd(n-a,n)*gcd(n-b,n)=n的k次方,其中a,b均滿足1<=a,b<=n
思路:新學的歐拉函數,這個函數euler(n)是用來尋找n前面有多少個與n互質的數。在本題中,講條件轉化一下就是:gcd(n-a,n)=x,gcd(n-b,n)=n/x,其中x是n的因子,每個a對應一個n-a,那麼也就可以轉換成:gcd(a,n)=x,gcd(b,n)=n/x。觀察容易發現:gcd(a/x,n/x)=1,也就是a/x,與n/x互質,問有多少個a(0<a<=n-1),那麼就是問n/x前面有多少個數字與n/x互質,就是直接調用歐拉函數
代碼:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#define maxn 100005
using namespace std;
#define ll long long
#define mod 1000000007
ll euler(ll x)
{
ll res = x;
for (ll i = 2; i <= x / i; i++)
if (x % i == 0)
{
res = res / i * (i - 1);
while(x % i == 0) x /= i;
}
if (x > 1) res = res / x * (x - 1);
return res;
}
int main()
{
ll n,k;
int cnt;
ll sum;
ll x,y;
ll ans[maxn];
while(scanf("%I64d%I64d",&n,&k)!=EOF)
{
if(n==1)
{
printf("1\n");
continue;
}
if(k>2)
{
printf("0\n");
continue;
}
if(k==2)
{
printf("1\n");
continue;
}
cnt=0;
memset(ans,0,sizeof(ans));
for(int i=1; i<=sqrt(n*1.0); i++)
{
if(n%i==0)
ans[cnt++]=i;
}
sum=0;
//cout<<cnt<<endl;
for(int i=0; i<cnt; i++)
{
if(n/ans[i]==ans[i])
{
x=euler(ans[i]);
y=x;
sum+=x*y;
sum=sum%mod;
}
else
{
x=euler(n/ans[i]);
y=euler(ans[i]);
//cout<<x<<" "<<y<<" ";
sum+=x*y*2;
sum=sum%mod;
}
}
printf("%I64d\n",sum);
}
return 0;
}