[CQOI2015]选数

题目描述

我们知道,从区间[L,H](L和H为整数)中选取N个整数,总共有(H-L+1)^N种方案。小z很好奇这样选出的数的最大公约数的规律,他决定对每种方案选出的N个整数都求一次最大公约数,以便进一步研究。然而他很快发现工作量太大了,于是向你寻求帮助。你的任务很简单,小z会告诉你一个整数K,你需要回答他最大公约数刚好为K的选取方案有多少个。由于方案数较大,你只需要输出其除以1000000007的余数即可。

题解

首先转化一下,变成求[L/k,R/k]的答案,此时公约数就变成了1。

但这样我们还是不能直接枚举GCD,它的范围是1e9的。

考虑区间长度最大为1e5,说明其中任意两个不同的数的GCD是要小于区间长度的。

所以我们设f[i]表示从区间中选n不完全相同的数GCDi的方案数。

按照套路容斥一下。

代码

#include<iostream>
#include<cstdio>
#define N 100002
using namespace std;
typedef long long ll;
const int mod=1000000007;
ll f[N],n,k,l,r;
inline ll rd(){
    ll x=0;char c=getchar();bool f=0;
    while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f?-x:x;
}
inline ll power(ll x,ll y){
    ll ans=1;
    while(y){
        if(y&1)ans=ans*x%mod;x=x*x%mod;y>>=1;
    }
    return ans;
}
int main(){
    n=rd();k=rd();l=rd();r=rd();
    r=r/k;l=(l-1)/k;
    for(int i=r-l;i>=1;--i){
        int x=(r/i-l/i+mod)%mod;
        f[i]=(power(x,n)-(x)+mod)%mod;
        for(int j=i*2;j<=r-l;j+=i)f[i]=(f[i]-f[j]+mod)%mod;
    }
    if(!l)f[1]=(f[1]+1)%mod;
    cout<<f[1];
    return 0;
}
原文地址:https://www.cnblogs.com/ZH-comld/p/10437903.html