[CQOI2015]选数

CQOI2015 选数

标签: 数学 莫比乌斯反演 递推 容斥原理


题目描述

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

输入输出格式

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

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

输入输出样例

输入样例#1:
2 2 2 4

输出样例#1:
3

说明

样例解释:
所有可能的选择方案:$(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

题解

方法一(莫比乌斯反演)

题意一句话描述:
$$\sum_{a1=L}^{H}\sum_{a2=L}^{H}…\sum_{an=L}^{H}[gcd(a1,a2,…,an)=k]$$
看到这个格式就比较熟悉了,我们不妨直接设:
$$f(x)=\sum_{a1=L}^{H}\sum_{a2=L}^{H}…\sum_{an=L}^{H}[gcd(a1,a2,…,an)=x]$$
$$F(x)=\sum_{x|d}f(d)=(\frac{H}{x}-\frac{L-1}{x})^{n}$$
(上界是$\frac{H}{x}$,下界是$\frac{L-1}{x}+1$)
那么
$$Ans=f(k)=\sum_{k|d}u(\frac{d}{k})F(d)$$
考虑枚举k的倍数:
$$Ans=\sum_{d=1}^{\frac{H}{k}}u(d)(\frac{H}{dk}-\frac{L-1}{dk})^{n}$$
做到这里就可以整除分块了,不过考虑到H达到$10^9$因此我们需要用杜教筛

方法二(容斥+递推)

那么注意到这道题有一个特殊的条件:$H-L<=10^5$
因此我们可以考虑到从这方面入手
一个简单的处理是先缩小L和H的范围:
令$l=\frac{L-1}{k}+1$, $r=\frac{R}{k}$那么问题转换成求$[l,r]$内$gcd(a1,a2,…,an)=1$的数对
然后这里存在一条性质:
在$[l,r]$中任意取不相同的两个数,这两个数的$gcd$不会超过$R-L$
证明:
设x,y两个数的gcd为d,则

$$x-y=d\ast p1-d\ast p2=d\ast (p1-p2)>d$$

证明完毕
有了上述的铺垫,我们可以想到设$f(x)$表示在$[l,r]$中选n个数且这n个数不完全相同且公约数为x的倍数的对数,那么
$$f(x)=d(x)^N-d(x)$$
其中$d(x)$表示区间内x的倍数个数
但是我们怎样求出公约数刚好为x的对数呢,我们发现,$f(x)$是包含了$f(2x),f(3x),….,f(kx)$的个数的,因此我们只要减去x的倍数的$f$就可以了,此时$f(x)$的含义就变成了gcd为x的个数了,因此我们可以倒推,最后答案为$f(1)$
注意,如果$l=1$的话最后我们答案要+1,因为存在$(1,1,1,1,…,1)$这个数对

代码(方法一)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<tr1/unordered_map>
#define ll long long
#define N 2000100
using namespace std;

const ll p = 1000000007;
int n, k, L, H, cnt = 0;
int pri[N], u[N], sum[N];
bool vis[N];
tr1::unordered_map<int, int> tu;

void get()
{
    u[1] = 1; u[0] = 0;
    int t = N - 100;
    for(int i = 2; i <= N; i ++)
    {
        if(!vis[i]) pri[++ cnt] = i, u[i] = -1;
        for(int j = 1; j <= cnt && i * pri[j] <= t; j ++)
        {
            vis[i * pri[j]] = true;
            if(i % pri[j]) u[i * pri[j]] = -u[i];
            else break; 
        }
    }
    for(int i = 1; i <= t; i ++) sum[i] = sum[i - 1] + u[i];
}

int djsu(int x)
{
    if(x <= 2e6) return sum[x];
    if(tu[x]) return tu[x];
    int ans = 1;
    for(int l = 2, r; l <= x; l = r + 1)
    {
        r = x / (x / l);
        ans -= (r - l + 1) * djsu(x / l);
    }
    return tu[x] = ans;
}

ll pow_mul(ll a, ll b, ll p)
{
    ll ans = 1;
    while(b)
    {
        if(b & 1) ans = ans * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return ans;
}

int main()
{
    scanf("%d%d%d%d", &n, &k, &L, &H);
    get();
    ll ans = 0;
    int le = (L - 1) / k, re = H / k;
    for(int l = 1, r; l <= re; l = r + 1) 
    {
        if(le / l == 0) r = re / (re / l); //除数不能为0 
        else r = min(le / (le / l), re / (re / l));
        ans += 1ll * (djsu(r) - djsu(l - 1)) * pow_mul(re / l - le / l, n, p);
        ans %= p;
    }
    while(ans < 0) ans += p; 
    printf("%lld", ans);
    return 0;
} 
/*
3 5 214147541 321411411
*/

心得

莫比乌斯函数本质是一个容斥函数,下界是要从1开始的,否则就不满足莫比乌斯函数的某些性质了,感谢peng-ym大佬的讲解


  转载请注明: iSecloud's Blog [CQOI2015]选数

 上一篇
poj1286--Necklace of Beads poj1286--Necklace of Beads
poj1286–Necklace of Beads标签:数学 置换 polya定理 题目描述给出三种颜色红绿蓝,对一串n(n<24)个小球的环染色,环可以旋转和翻转,问最终可能有多少不同的染色方案。 输入输出格式InputThe i
2019-02-22
下一篇 
[SDOI2014]数表 [SDOI2014]数表
[SDOI2014]数表标签:数学 莫比乌斯反演 树状数组 题目描述有一张N*m的数表,其第i行第j列(1 < =i < =n,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和。给定a,计算数表中
2019-02-17