【刷题】BZOJ 3930 [CQOI2015]选数

Description

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

Input

输入一行,包含4个空格分开的正整数,依次为N,K,L和H。

Output

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

Sample Input

2 2 2 4

Sample Output

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%的数据,1≤N,K≤10^9,1≤L≤H≤10^9,H-L≤10^5

Solution

我用的是莫比乌斯反演加杜教筛
这题本来不需要莫反的,但最近都在练习莫反,那就用莫反做了
设\(F(d)\)代表在\([L,R]\)中选N个数,它们的gcd为d及其倍数的方案数
设\(f(d)\)代表在\([L,R]\)中选N个数,它们的gcd为d的方案数
\[F(n)=\sum_{n|d}f(d)=(\lfloor \frac{R}{n} \rfloor-\lfloor \frac{L-1}{n} \rfloor)^N\]
上面式子的左边一半根据定义,右边一半的原因如下:
\(\lfloor \frac{R}{n} \rfloor\)其实是1到R中有多少个数整除n,\(\lfloor \frac{L-1}{n} \rfloor\)类似,那么它们相减之后,得到的就是\([L,R]\)中有多少个数可以整除n。根据题目的第一句话,我们知道选数是有序的,并且可以重复选。所以我们在得到了有多少个数整除n后,只要在里面有序地任选N个数,方案数是\((\lfloor \frac{R}{n} \rfloor-\lfloor \frac{L-1}{n} \rfloor)^N\),它们可以保证它们的gcd一定为n或n的倍数
接下来继续推
\[f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)=\sum_{n|d}\mu(\frac{d}{n})(\lfloor \frac{R}{d} \rfloor-\lfloor \frac{L-1}{d} \rfloor)^N\]
改变枚举方式
\[f(n)=\sum_{d=1}^{\lfloor \frac{R}{n} \rfloor}\mu(d)(\lfloor \frac{R}{nd} \rfloor-\lfloor \frac{L-1}{nd} \rfloor)^N\]
后面的东西整除分段加快速幂,前面的东西杜教筛
关于杜教筛,这里只给一个式子,有兴趣可以百度
\[S(n)=1-\sum_{i=2}^nS(\lfloor \frac{n}{i} \rfloor)\ \ \ \ (S(n)=\sum_{i=1}^n\mu(i))\]

#include<bits/stdc++.h>
#define ll long long
const int Mod=1e9+7,MAXN=1e6+10,inf=0x3f3f3f3f;
int prime[MAXN],cnt,vis[MAXN],s[MAXN],mu[MAXN];
std::map<ll,ll> M;
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char c='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(c!='\0')putchar(c);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void init()
{
    memset(vis,1,sizeof(vis));
    vis[0]=vis[1]=0;
    mu[1]=1;
    for(register int i=2;i<MAXN;++i)
    {
        if(vis[i])
        {
            prime[++cnt]=i;
            mu[i]=-1;
        }
        for(register int j=1;j<=cnt&&i*prime[j]<MAXN;++j)
        {
            vis[i*prime[j]]=0;
            if(i%prime[j])mu[i*prime[j]]=-mu[i];
            else break;
        }
    }
    for(register int i=1;i<MAXN;++i)s[i]=s[i-1]+mu[i];
}
inline ll qexp(ll a,ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1)res=res*a%Mod;
        a=a*a%Mod;
        b>>=1;
    }
    return res;
}
inline ll MuSum(int x)
{
    if(x<MAXN)return s[x];
    if(M[x])return M[x];
    ll res=1;
    for(register int i=2;;)
    {
        if(i>x)break;
        int j=x/(x/i);
        res-=(ll)(j-i+1)*(ll)MuSum(x/i);
        i=j+1;
    }
    return M[x]=res;
}
inline ll solve(int N,int L,int H)
{
    ll res=0;
    for(register int i=1;;)
    {
        if(i>H)break;
        int j=min(H/(H/i),L/i?L/(L/i):inf);
        (res+=qexp((ll)(H/i-L/i),N)*(ll)(MuSum(j)-MuSum(i-1))%Mod)%=Mod;
        i=j+1;
    }
    return (res+Mod)%Mod;
}
int main()
{
    init();
    int N,K,L,H;
    read(N);read(K);read(L);read(H);
    write(solve(N,(L-1)/K,H/K),'\n');
    return 0;
}

原文地址:https://www.cnblogs.com/hongyj/p/8540447.html

时间: 2024-08-11 09:38:12

【刷题】BZOJ 3930 [CQOI2015]选数的相关文章

BZOJ 3930: [CQOI2015]选数

3930: [CQOI2015]选数 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1130  Solved: 532[Submit][Status][Discuss] Description 我们知道,从区间[L,H](L和H为整数)中选取N个整数,总共有(H-L+1)^N种方案.小z很好奇这样选出的数的最大公约数的规律,他决定对每种方案选出的N个整数都求一次最大公约数,以便进一步研究.然而他很快发现工作量太大了,于是向你寻求帮助.你的任务很简

BZOJ 3930: [CQOI2015]选数 递推

3930: [CQOI2015]选数 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=3930 Description 我们知道,从区间[L,H](L和H为整数)中选取N个整数,总共有(H-L+1)^N种方案.小z很好奇这样选出的数的最大公约数的规律,他决定对每种方案选出的N个整数都求一次最大公约数,以便进一步研究.然而他很快发现工作量太大了,于是向你寻求帮助

【递推】BZOJ 3930: [CQOI2015]选数

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

BZOJ 3930 CQOI2015 选数 莫比乌斯反演

题目见 http://pan.baidu.com/s/1o6zajc2 此外不知道H-L<=10^5这个条件是干嘛的.... #include <map> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 10001000 #define INF 0x3f3f3f3f #define MOD 1000000007 u

3930: [CQOI2015]选数|递推|数论

题目让求从区间[L,H]中可重复的选出n个数使其gcd=k的方案数 转化一下也就是从区间[?Lk?,?Hk?]中可重复的选出n个数使其gcd=1的方案数 然后f[i]表示gcd=i的方案数,考虑去掉所有的数都是重复的情况,这种情况最后在判断一下加上 f[i]=sum?∑i|jf[j] #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<c

BZOJ 2734 集合选数(状态压缩DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2734 题意:给出一个由1到n的数字组成的集合.定义合法子集为若x在子集中则2x.3x均不能在子集中.求有多少个合法的子集. 思路: 1   3    9 2   6    12 4   12   36 对于上面的矩阵,我们发现就等价于不选相邻数字的方案数.因此枚举每个还没有用到的数字,建立以该数字为左上角的矩阵.接着就是状态压缩DP. int a[N][N]; i64 f[2][1<<

leecode刷题(8)-- 两数之和

leecode刷题(8)-- 两数之和 两数之和 描述: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样的元素. 示例: 给定 nums = [2, 7, 11, 15], target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1] 思路: 这道题其实很简单,我们可以直接用暴力搜索的方法,设置双重

BZOJ3930 [CQOI2015]选数 【容斥】

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

Luogu P3172 [CQOI2015]选数

这题的反演做法好像很不可食用啊还得套一个杜教筛 我们注意到题目一个重要的性质:\(H-L\le10^5\),看起来可以好好利用一下. 我们首先转化问题,类似于许多和\(\gcd\)有关的问题,我们将原来的最大公约数\(K\)想办法变成\(1\) 这个怎么处理呢,其实很简单,将\(L\)变为\(\lceil \frac{L}{K}\rceil\),将\(R\)变为\(\lfloor\frac{H}{K}\rfloor\). 显然这样我们把问题转化为:在\([L,H]\)种取\(N\)次数使它们的\