/*
题目大意:有n个物品,分成f份,这f份的最大公约数是1的种类数目
记答案为P(n,f,1)
则有sigma(P(n,f,i)) = C(n-1,f-1)(n件物品分为f份的总方法数)
注意到P(n,f,i) = P(n/i,f,1).
我们可以记P(n,f,1)为g(n,f)
则有sigma(d|n) g(d,f) = C(n-1,f-1).
令右边为f(n,f)
则可以利用mobius函数简化计算.
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
#define MAXN 100010
#define MOD 1000000007
LL mul[MAXN];
LL in[MAXN];
LL v[MAXN];
void extend_gcd(LL a,LL b,LL &d,LL &x,LL &y)
{
if(!b)
{
d=a;
x=1;
y=0;
}else{
extend_gcd(b,a%b,d,y,x);
y-=x*(a/b);
}
}
LL inv(LL a,LL n)
{
LL d,x,y;
extend_gcd(a, n, d, x, y);
return d == 1? (x+n)%n:-1;
}
void init()
{
mul[0]=1;
in[0]=1;
for(int i=1;i<MAXN;++i)
{
mul[i]=(mul[i-1]*(LL)i)%MOD;
in[i]=inv(mul[i],MOD);
}
//calculate mobius function
v[1]=1;
v[2]=-1;
v[3]=-1;
for(int i=4;i<MAXN;++i)
{
int tmp = i;
int cnt = 0;
for(int j=2;j*j<=i;++j)
{
if(tmp==1) break;
if(tmp%j==0)
{
cnt ++;
tmp/=j;
if(tmp%j==0)
{
cnt = -1;
}
}
if(cnt==-1)
break;
}
if(cnt==-1)
{
v[i]=0;
}
else
{
if(tmp!=1) cnt++;
if(cnt%2==1) v[i]=-1;
else v[i]=1;
}
}
//printf("%lld\n",v[30]);
//for(int i=1;i<=20;++i)
//printf("%lld\n",v[97]);
//printf("\n");
}
LL calc(int n,int k)
{
if(n<0) return 0;
if(k>n) return 0;
if(k<0) return 0;
LL ans=1;
ans = (ans*mul[n])%MOD;
ans = (ans*in[k])%MOD;
ans = (ans*in[n-k])%MOD;
return (ans+MOD)%MOD;
}
LL solve(int n,int f)
{
LL ans=0;
for(int i=1;i*i<=n;++i)
{
if(n%i==0)
{
LL tmp = v[n/i];
tmp = (MOD + tmp*calc(i-1,f-1))%MOD;
ans = (ans + tmp)%MOD;
if(i*i!=n)
{
tmp = v[i];
tmp = (MOD + tmp*calc((n/i)-1,f-1))%MOD;
ans = (ans + tmp)%MOD;
}
}
}
return ans;
}
int main()
{
init();
int Q;
scanf("%d",&Q);
while(Q--)
{
int n,f;
scanf("%d%d",&n,&f);
printf("%lld\n",solve(n,f));
}
return 0;
}
439 E. Devu and Birthday Celebration
最新推荐文章于 2020-10-24 20:57:02 发布