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 }
整除分块的时候要判断是不是0啊......