LOJ#2095 选数

给定n,k,l,r

问从[l, r]中选出n个数gcd为k的方案数。

解:稍微一想就能想到反演,F(x)就是[l, r]中x的倍数个数的n次方。

后面那个莫比乌斯函数随便怎么搞都行,当然因为这是杜教筛的题就杜教筛了。

然后写一写,交上去80分......

然后枚举一下d是k的多少倍,我们发现F(x)的计算式[(r / x) - ((l - 1) / x)]n可以整除分块...

然后就做完了。

 1 #include <cstdio>
 2 #include <map>
 3 #include <algorithm>
 4 
 5 typedef long long LL;
 6 const int N = 1000010, T = 1000008;
 7 const LL MO = 1000000007;
 8 
 9 std::map<LL, LL> mp;
10 int p[N], top, miu[N];
11 LL n, k, l, r, Miu[N], L, R;
12 bool vis[N];
13 
14 inline void getp(int n) {
15     miu[1] = 1;
16     for(int i = 2; i <= n; i++) {
17         if(!vis[i]) {
18             p[++top] = i;
19             miu[i] = -1;
20         }
21         for(int j = 1; j <= top && i * p[j] <= n; j++) {
22             vis[i * p[j]] = 1;
23             if(i % p[j] == 0) {
24                 break;
25             }
26             miu[i * p[j]] = -miu[i];
27         }
28     }
29     for(int i = 1; i <= n; i++) {
30         Miu[i] = Miu[i - 1] + miu[i];
31     }
32     return;
33 }
34 
35 inline LL qpow(LL a, LL b) {
36     LL ans = 1;
37     a %= MO;
38     while(b) {
39         if(b & 1) ans = ans * a % MO;
40         a = a * a % MO;
41         b = b >> 1;
42     }
43     return ans;
44 }
45 
46 LL getMiu(LL x) {
47     if(x <= 0) return 0;
48     if(x <= T) return Miu[x];
49     if(mp.count(x)) return mp[x];
50     LL ans = 1;
51     for(LL i = 2, j; i <= x; i = j + 1) {
52         j = x / (x / i);
53         ans -= (j - i + 1) % MO * getMiu(x / i) % MO;
54         ans %= MO;
55     }
56     return mp[x] = (ans + MO) % MO;
57 }
58 
59 LL F(LL x) {
60     LL temp = (R / x) - (L / x);
61     return qpow(temp, n);
62 }
63 
64 int main() {
65     getp(T);
66     scanf("%lld%lld%lld%lld", &n, &k, &l, &r);
67     LL ans = 0;
68     L = (l - 1) / k, R = r / k;
69     for(LL i = 1, j; i <= R; i = j + 1) {
70         if(L / i) j = std::min(R / (R / i), L / (L / i));
71         else if(R / i) j = R / (R / i);
72         else j = R;
73         ans += F(i) * (getMiu(j) - getMiu(i - 1)) % MO;
74         ans %= MO;
75     }
76     printf("%lld\n", (ans + MO) % MO);
77 
78     return 0;
79 }
AC代码

整除分块的时候要判断是不是0啊......

posted @ 2019-02-27 16:01  huyufeifei  阅读(154)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜