BZOJ3930 【CQOI2015】选数

本文详细介绍了如何通过容斥原理和幂运算解决一道看似复杂的数学问题。作者巧妙地定义了$f[i]$表示特定条件下的方案数,并通过反向遍历和减法操作高效地计算最终答案。文章最后讨论了Mobius反演的适用场景,虽然此处未使用,但提供了对更复杂数学问题的潜在解决方案。代码简洁高效,展示了算法的实用性和快速实现能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

感觉水水的一道题。
网上说什么mobius反演,但是感觉很麻烦,然后就感觉可以容斥乱搞,后来发现不用容斥。
如果我们用f[i]表示gcd刚好为k*i的选数方案,那么f[1]就是答案,然后我们就for i = 100000 to 1,从大往小算。
对于每一个i,先算在这个区间里面有多少个k*i的倍数,然后N次方之。
这就是gcd至少为k*i的方案数
然后减去f[i*j] j = 1,2,3….MAXJ。
i*j到100000就好了,因为这个区间最多只有100000长。
可能i*j在100000以上还会有需要减掉的,我们考虑计算这些数对答案的贡献,首先同一个gcd只会有1个数,这些gcd的个数就是在原区间里面除以K>100000且为i的倍数的数,不是很好求吗。。
然后就A了,跑得飞快,代码还短,内存还小。

不知道mobius反演是用来干什么的←_←

#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <cstdlib>
#include <cstring>
#define MOD 1000000007
#ifdef WIN32
#define LL "%I64d"
#else 
#define LL "%lld"
#endif
using namespace std;

long long qpow(long long x,int y) {
    if (y == 0) return 1;
    if (y == 1) return x;
    long long res = qpow(x,y / 2);
    res = (res * res) % MOD;
    res = (res * qpow(x, y % 2)) % MOD;
    return res;
}

int get_sum(int l,int r,long long k) {
    if (l > r) return 0;
    int ll = l / k;
    if (l % k) ll++;
    return r / k - ll + 1;
}
int n,k,l,r;
long long f[200010];
int main() {
    scanf("%d%d%d%d",&n,&k,&l,&r);
    int ll = l / k;
    if (ll % k) ll ++;
    ll = max(ll,100001);
    for (int i=100000;i>=1;i--) {
        long long cur = (long long)k * i;
        long long s = get_sum(l,r,cur);
        f[i] = qpow(s,n);
        long long ss = get_sum(ll,r / k,i);
        f[i] = (f[i] - ss + MOD) % MOD;
        for (int j=2*i;j<=100000;j+=i) {
            f[i] = (f[i] - f[j] + MOD) % MOD;
        }
    }
    printf(LL"\n",f[1]);
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值