luogu P3172 [CQOI2015]选数 |容斥原理
题目描述
我们知道,从区间 \([L,H]\)(\(L\) 和 \(H\) 为整数)中选取 \(N\) 个整数,总共有 \((H-L+1)^N\) 种方案。小 z 很好奇这样选出的数的最大公约数的规律,他决定对每种方案选出的 \(N\) 个整数都求一次最大公约数,以便进一步研究。然而他很快发现工作量太大了,于是向你寻求帮助。你的任务很简单,小 z 会告诉你一个整数 \(K\),你需要回答他最大公约数刚好为 \(K\) 的选取方案有多少个。
由于方案数较大,你只需要输出其除以 \(10^9+7\) 的余数即可。
输入格式
输入一行,包含四个空格分开的正整数,依次为 \(N,K,L,H\)。
输出格式
输出一个整数,为所求方案数除以 \(10^9 + 7\) 的余数。
\(f[i]\)表示选出的数的最大公约数\(i\)且选出的数不全相同的方案数
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int N=1e5+5,mod=1e9+7;
inline int read(){
int x=0,f=1; char ch=getchar();
while(ch>'9'||ch<'0'){ if(ch=='-')f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
return x*f;
}
int f[N];
inline int ksm(int a, int b) {
int res=1;
while(b){
if(b&1)res=res*a%mod;
a=a*a%mod; b>>=1;
}
return res;
}
signed main(){
int n=read(),k=read(),l=read(),h=read();
if(l%k)l=l/k+1; else l/=k; h/=k;
if(l>h){ puts("0"); return 0; }
for(int i=1;i<=h-l;i++){
int L=l,R=h;
if(L%i)L=L/i+1; else L/=i; R/=i;
if(L>R)continue;
f[i]=(ksm(R-L+1,n)-(R-L+1)+mod)%mod;
}
for(int i=h-l;i;i--) for(int j=(i<<1);j<=h-l;j+=i)f[i]=(f[i]-f[j]+mod)%mod;
if(l==1)f[1]=(f[1]+1)%mod;
cout<<f[1]<<endl;
return 0;
}
不以物喜,不以己悲
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步