【BZOJ】3930: [CQOI2015]选数

题意

从区间\([L, R]\)\(N\)个数(可以重复),问这\(N\)个数的最大公约数是\(K\)的方案数。(\(1 \le N, K \le 10^9, 1 \le L \le R \le 10^9, H-L \le 10^5\)

分析

好神的题。注意\(H-L \le 10^5\)这个条件,则假设\(N\)个数不全相同,那么他们的最大公约数小于最大和最小的两个数之差,证明很简单,设\(d\)为最大公约数,则\(dk_2 -dk_1 = d( k_2 - k_1 ) > d\)

题解

因此我们可以先算出\(N\)个数不全相同的方案数,然后再特判一下全相同的情况,加起来就是答案了。
计算前者我们可以将边界除以\(K\),然后在新边界里面找最大公约数为\(1\)的方案数。由于新边界最大于最小之差不超过\(10^5\),因此我们暴力枚举一下这些公约数,用容斥剪掉重复的即可。也就是说:
\[d_i = sum - \sum_{i|j} d_j\]
\(sum\)的计算注意剪掉\(N\)个数相同的方案。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mo=1000000007;
int ipow(int a, int b) {
    int x=1;
    a%=mo;
    for(; b; b>>=1, a=(ll)a*a%mo)
        if(b&1) x=(ll)x*a%mo;
    return x;
}
int d[100005];
int main() {
    int N, K, L, R, MX, flag=0;
    scanf("%d%d%d%d", &N, &K, &L, &R);
    if(L<=K && K<=R) flag=1;
    L=(L-1)/K, R=R/K;
    MX=R-L;
    for(int i=MX; i>=1; --i) {
        int &now=d[i];
        ll l=L/i, r=R/i, t=r-l;
        if(l<r) {
            now=(ipow((t), N)-t+mo)%mo;
            for(int j=i<<1; j<=MX; j+=i) now=(now-d[j]+mo)%mo;
        }
    }
    printf("%d\n", d[1]+flag);
    return 0;
}
posted @ 2015-11-22 17:52 iwtwiioi 阅读(...) 评论(...) 编辑 收藏