luogu3172 && bzoj3930 [CQOI2015]选数

该博客介绍了CQOI2015中的选数问题,探讨了如何在给定区间[L, H]内,找出最大公约数为K的N个整数的选取方案数量。博主提供了数学方法来解决这个问题,通过计算互质的选取方案,利用快速幂优化了算法,时间复杂度为O((H-L)logN)。并给出了样例解释及思路总结,建议不会莫反方法的读者尝试使用排列组合思路解题。" 121238968,10387934,操作系统:进程互斥的硬件解决方案,"['操作系统', '并发控制', '硬件机制', '多处理机']
摘要由CSDN通过智能技术生成

luogu3172
bzoj3930


题目

3930:[CQOI2015]

TimeLimit:10Sec
MemoryLimit:512MB

Description

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

Input

输入一行,包含 4 个空格分开的正整数,依次为NKLH

Output

输出一个整数,为所求方案数。

SampleInput

2 2 2 4

SampleOutput

3

HINT

样例解释
所有可能的选择方案:(2, 2), (2, 3), (2, 4), (3, 2), (3, 3), (3, 4), (4, 2), (4, 3), (4, 4)
其中最大公约数等于2的只有3组:(2, 2), (2, 4), (4, 2)
100%1N,K1091LH109HL105


题解

看到 gcd ,第一反应这应该是莫反。
然而,这可以用数学方法。
没想到吧,我也没想到。
l=LK h=HK
首先,我们可以把题目转化为从区间 [l,h] 中选取 N 个整数,求N个整数互质的选取方案有多少个。(因为仅当是 K 的倍数是才可以被选)
我们假设N个整数不完全相同。
f(i) 表示 i|gcd 的方案数, g(i) 表示 i=gcd 的方案数。
ll=li hh=hi
f(i)=(hhll+1)n(hhll+1) (因为当且仅当是 i 的倍数时可以被选)
g(i)=f(i)i|jg(j)
那么从 HL 逆推到 1 即可。
f(i)用快速幂, ll=1 g(1) 记得 +1
时间复杂度 O((HL)logN)


总结

这道题其实可以莫反,也可以数学方法。但是我的第一反应仍是数学方法。这种题目如果不会莫反,就不要去惹它。想一想骗分的排列组合,说不定就过了。
不想新建分类,就当做是莫反。


标程

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MOD=1000000007;
const int N=100005;
int n, k, l, h, ans;
int ll, hh, f[N];
int power(int a, int b)
{
    int c=1;
    while (b)
    {
        if (b&1) c=1LL*c*a%MOD;
        b>>=1; a=1LL*a*a%MOD;
    }
    return c;
}
void work()
{
    scanf("%d%d%d%d", &n, &k, &l, &h);
    l=(l-1)/k+1; h/=k;
    for (int i=1; i<=h-l; i++)
    {
        ll=(l-1)/i+1; hh=h/i;
        f[i]=(power(hh-ll+1, n)-(hh-ll+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;
    printf("%d\n", f[1]);
}
int main()
{
    work();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值