[数论]Coprime

题目描述

对于两个整数k 和m,如果k 和m 的最大公约数为1,则k 和m 互质。给出两个正整
数n 和m(m≤n),定义f(n,m)为1~n!中与m!互质的数的个数。其中n!=1*2*3*..*(n-1)*n。
Task:给定n 和m,要求计算f(n,m)。

Input

本题设多组数据。
输入文件的第一行有一个整数T(1≤T≤100000),表示有T 组数据。
接下来有T 行,每行两个整数n 和m(2≤n≤100000,2≤m≤n)。

Output

输出文件包含T 行,每行一个整数,表示f(n,m)。
由于答案过大,所以你只要输出f(n,m) mod 131071。
131071 是M17(梅森素数,2^17-1)。

Sample Input

1
3 2

Sample Output

3

Data Constraint

Hint

数据约定:
对于50%的数据,T=1,2≤N≤10
对于80%的数据,T=1,2≤N≤100000
对于100%的数据,1≤T≤100000,2≤N≤100000

分析

话说我比赛前说什么就考什么啊
φ∏
首先我们看到求互质数就知道肯定和欧拉函数有关
然后我们通过一个简单的思维推理即可知:
φm=φ(m+1~2m)
(更相减损法)
那么我们也只要知道φm!是多少即可,因为公式十分明显:
n!/m!*φm!
然后欧拉函数的分解式为:
m!*∏(1-1/p) [p为质数]
那么1/m!和m!抵消得
n!*∏(1-1/p)
n!简单,预处理
但是欧拉函数的递推式要考虑一下,设f(x)=∏(1-1/p)
因为m!和m-1!只差一个m的积,显然
若x为质数则f(x)=f(x-1)*(1-1/x)
否则f(x)=f(x-1)
然后除法因为要模所以搞个逆元即可
感谢题解dalao
感谢欧拉函数讲解

#include 
#include 
#define rep(i,a,b) for (i=a;i<=b;i++)
#define q 131071
using namespace std;
long long a[100001],b[100001],p[100001];
bool c[100001];
int cnt=0;
int t,n,m;
int i,j;
long long power(long long x,long long k)
{
    long long s=1;
    while (k)
    {
        if (k&1) s=s*x%q;
        x=x*x%q;
        k=k>>1;
    }
    return s;
}
int main()
{
    freopen("coprime.in","r",stdin);
    freopen("coprime.out","w",stdout);
    a[1]=1;
    rep(i,2,100000) a[i]=a[i-1]*i%q;
    b[1]=1;
    rep(i,2,100000)
    {
        b[i]=b[i-1];
        if (!c[i])
        {
            b[i]=b[i]*(i-1)%q*power(i,q-2)%q;
            p[++cnt]=i;
        }
        rep(j,1,cnt)
        {
            if (i*p[j]>100000) break;
            c[i*p[j]]=1;
            if (i%p[j]==0) break;
        }
    }
    scanf("%d",&t);
    rep(i,1,t)
    {
        scanf("%d%d",&n,&m);
        printf("%lld\n",a[n]*b[m]%q);
    }
}

你可能感兴趣的:([数论]Coprime)