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

题目

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


分析

那么也就是在求 [ ⌈ l k ⌉ ∼ ⌊ r k ⌋ ] 中 选 取 [\lceil\frac{l}{k}\rceil\sim\lfloor\frac{r}{k}\rfloor]中选取 [klkr]n 个 整 数 , 最 大 公 约 数 刚 好 为 1 的 选 取 方 案 数 个整数,最大公约数刚好为1的选取方案数 ,1
那么之后怎么做呢,因为 r − l r-l rl比较小,所以说可以选择枚举因数 i i i,那么缩小的范围就变为 [ ⌈ ⌈ l k ⌉ i ⌉ ∼ ⌊ ⌊ r k ⌋ i ⌋ ] [\lceil\frac{\lceil\frac{l}{k}\rceil}{i}\rceil\sim\lfloor\frac{\lfloor\frac{r}{k}\rfloor}{i}\rfloor] [iklikr],那么其中的数就是对于因数为 i i i时,范围内除以 i i i的数,设 d p [ i ] dp[i] dp[i]为选取的数公因数是 i i i的个数,那么 d p [ i ] = ( ⌊ ⌊ r k ⌋ i ⌋ − ⌈ ⌈ l k ⌉ i ⌉ + 1 ) n − ( ⌊ ⌊ r k ⌋ i ⌋ − ⌈ ⌈ l k ⌉ 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的倍数, d p [ i ] − = ∑ j = 2 x d p [ i j ] dp[i]-=\sum_{j=2}^{x}dp[ij] dp[i]=j=2xdp[ij],这样就可以求出最大公因数是 i i i的个数,时间复杂度 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]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值