洛谷4562:[JXOI2018]游戏——题解

https://www.luogu.org/problemnew/show/P4562

https://www.lydsy.com/JudgeOnline/problem.php?id=5323

(BZOJ有点卡常数过不去。)

实际上我们只需要求出l~r区间内有多少数是满足不存在l~r内的数a使得i*a=这个数

我们欧拉筛实际上就是一个数可以分解成的最大的两个数(其中一个是最大质数)的乘积,于是我们判断那个合数是否<l且这个数是否在l~r的区间内,如果满足则这个数就是我们要求的。

然后数学公式导一波就行了。

#include<cmath>
#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e7+5;
const int p=1e9+7;
int l,r,tot,su[N],cnt;
ll jc[N],inv[N];
bool he[N];
int qpow(int k,int n){
    int res=1;
    while(n){
    if(n&1)res=(ll)res*k%p;
    k=(ll)k*k%p;n>>=1;
    }
    return res;
}
void Euler(int n){
    for(int i=2;i<=n;++i){    
    if(!he[i]){
        su[++tot]=i;
        if(l<=i&&i<=r)++cnt;
    }
    bool ok=0;
    for(int j=1;j<=tot;++j){
        int q=i*su[j];
        if(q>n)break; 
        he[q]=1;
        if(l<=q&&q<=r&&i<l)++cnt;
        if(i%su[j]==0)break;
    }
    }
}
ll C(int n,int m){
    return jc[n]*inv[m]%p*inv[n-m]%p;
}
void init(int n){
    jc[0]=1;
    for(int i=1;i<=n;++i)jc[i]=jc[i-1]*i%p;
    inv[n]=qpow(jc[n],p-2);
    for(int i=n-1;i;i--)inv[i]=inv[i+1]*(i+1)%p;
    inv[0]=1;
}
int main(){
    scanf("%d%d",&l,&r);
    init(r);
    ll ans=0;
    if(l==1){
    for(int i=1;i<=r;++i){
        ans=(ans+i*jc[r-1])%p;
    }
    printf("%lld\n",ans);
    }else{
    Euler(r);
    int n=r-l+1;
    for(int i=cnt;i<=n;++i){
        ans=(ans+i*C(n-cnt,i-cnt)%p*jc[i-1]%p*jc[n-i]%p*cnt%p)%p;
    }
    printf("%lld\n",ans);
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

猜你喜欢

转载自www.cnblogs.com/luyouqi233/p/9078927.html
今日推荐