#快速幂,eratosthenes筛#bzoj 3930 洛谷 3172 选数

本文探讨了从指定区间内选择整数,使得这些整数的组合最大公约数等于给定值的方案数量。通过数学分析和算法设计,详细解释了如何在考虑枚举因数的情况下,高效计算出满足条件的组合总数。

题目

从区间[l∼r][l\sim r][lr]中选取nnn个整数,总共有(r−l+1)n(r-l+1)^n(rl+1)n种方案。问最大公约数刚好为kkk的选取方案有多少个。


分析

那么也就是在求[⌈lk⌉∼⌊rk⌋]中选取[\lceil\frac{l}{k}\rceil\sim\lfloor\frac{r}{k}\rfloor]中选取[klkr]n个整数,最大公约数刚好为1的选取方案数个整数,最大公约数刚好为1的选取方案数,1
那么之后怎么做呢,因为r−lr-lrl比较小,所以说可以选择枚举因数iii,那么缩小的范围就变为[⌈⌈lk⌉i⌉∼⌊⌊rk⌋i⌋][\lceil\frac{\lceil\frac{l}{k}\rceil}{i}\rceil\sim\lfloor\frac{\lfloor\frac{r}{k}\rfloor}{i}\rfloor][iklikr],那么其中的数就是对于因数为iii时,范围内除以iii的数,设dp[i]dp[i]dp[i]为选取的数公因数是iii的个数,那么dp[i]=(⌊⌊rk⌋i⌋−⌈⌈lk⌉i⌉+1)n−(⌊⌊rk⌋i⌋−⌈⌈lk⌉i⌉+1)dp[i]=(\lfloor\frac{\lfloor\frac{r}{k}\rfloor}{i}\rfloor-\lceil\frac{\lceil\frac{l}{k}\rceil}{i}\rceil+1)^n-(\lfloor\frac{\lfloor\frac{r}{k}\rfloor}{i}\rfloor-\lceil\frac{\lceil\frac{l}{k}\rceil}{i}\rceil+1)dp[i]=(ikrikl+1)n(ikrikl+1)
那问题是我们求的是1,那可以干什么呢,我们枚举i的倍数,dp[i]−=∑j=2xdp[ij]dp[i]-=\sum_{j=2}^{x}dp[ij]dp[i]=j=2xdp[ij],这样就可以求出最大公因数是iii的个数,时间复杂度O(2×(r−l)log⁡2(r−l))O(2\times (r-l)\log_2(r-l))O(2×(rl)log2(rl))


代码

#include <cstdio>
#define rr register
using namespace std;
const int mod=(int)1e9+7;
int n,k,l,r,dp[100001];
inline signed ksm(long long x,int y){
    rr long long ans=1;
    while (y){
        if (y&1) (ans*=x)%=mod;
        (x*=x)%=mod; y>>=1;
    }
    return ans;
}
signed main(){
    scanf("%d%d%d%d",&n,&k,&l,&r);
    l=l/k+(l%k>0),r/=k;
    if (l>r) return !putchar(48);
    for (rr int i=1;i<=r-l;++i){
        rr int L=l/i+(l%i>0),R=r/i;
        if (L>R) break;
        dp[i]=(ksm(R-L+1,n)-R+L-1+mod)%mod;
    }
    for (rr int i=r-l;i;--i)
    for (rr int j=2;i*j<=r-l;++j)
    (dp[i]-=dp[i*j]-mod)%=mod;
    if (l==1) (++dp[1])%=mod;//如果最后扩散到的范围在1上,那么1要多加
    return !printf("%d",dp[1]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值