zoukankan      html  css  js  c++  java
  • 【题解】CQOI2015选数

      这题做的时候接连想错了好多次……但是回到正轨上之后依然是一个套路题。(不过这题好像有比莫比乌斯反演更好的做法,莫比乌斯反演貌似是某种能过的暴力ヽ(´ー`)┌)不过能过也就行了吧哈哈。

      首先我们把数字的范围要进行缩小:最大公约数为 (K) 那自然所有选出来的数都必须是 (K) 的倍数。所以我们改选数为选择是 (K) 的多少倍。然后由于是最大公约数,所以选出来的这些数必须最大公约数等于(1)。实际上多个数的最大公约数( = 1)完全可以和两个数的最大公约数 ( = 1) 用一样的方法去反演。只不过这题由于数据范围非常的大,所以处理 (mu) 的前缀和必须要使用杜教筛。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 1000300
    #define db double
    #define int long long
    int maxx = maxn - 1e2, mod = 1e9 + 7;
    int N, K, L, H, ans, Sum[maxn];
    int tot, pri[maxn];
    map <int, int> Map;
    bitset <maxn> is_prime;
    
    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    int qpow(int x, int times)
    {
        int base = 1; x %= mod;
        for(; times; times >>= 1, x = (x * x) % mod)
            if(times & 1) base = (base * x) % mod;
        return base;
    }
    
    void Get_Mu()
    {
        Sum[1] = 1;
        for(int i = 2; i <= maxx; i ++)
        {
            if(!is_prime[i]) pri[++ tot] = i, Sum[i] = -1;
            for(int j = 1; j <= tot; j ++)
            {
                int tem = i * pri[j];
                if(tem > maxx) break;
                is_prime[tem] = 1;
                if(!(i % pri[j])) { Sum[tem] = 0; break; }
                else Sum[tem] = - Sum[i];
            }
        }
        for(int i = 1; i <= maxx; i ++) Sum[i] = (Sum[i] + Sum[i - 1]) % mod;
    }
    
    int Mu(int x)
    {
        if(x <= maxx) return Sum[x];
        if(Map[x]) return Map[x];
        int ret = 0;
        for(int l = 2, r; l <= x; l = r + 1)
        {
            r = x / (x / l);
            ret = (ret + (r - (l - 1)) * Mu(x / l) % mod) % mod; 
        }
        return Map[x] = (1 - ret + mod) % mod;
    }
    
    int Solve(int n, int m)
    {
        int ret = 0;
        for(int l = 1, r; l <= m; l = r + 1)
        {
            if(n / l) r = min((n / (n / l)), (m / (m / l)));
            else r = (m / (m / l));
            ret += qpow(m / l - n / l, N) % mod * (Mu(r) - Mu(l - 1)) % mod;
            ret %= mod;
        }
        return ret;
    }
    
    signed main()
    {
        N = read(), K = read(), L = read(), H = read(), ans = 0;
        Get_Mu();
        int l = floor((db) (L - 1) / (db) K), r = floor((db) H / (db) K);
        ans = Solve(l, r);
        printf("%lld
    ", (ans + mod) % mod);
        return 0;
    }
  • 相关阅读:
    hdu 1548 升降梯
    hdu 2544 hdu 1874 poj 2387 Dijkstra 模板题
    hdu 4463 有一条边必须加上 (2012杭州区域赛K题)
    poj 1679 判断MST是不是唯一的 (次小生成树)
    poj 1751 输出MST中新加入的边
    poj 2349 求MST中第S大的权值
    HDU 4389 X mod f(x) (数位DP)
    HDU 5908 Abelian Period (暴力)
    HDU 5907 Find Q (水题)
    HDU 4514 湫湫系列故事――设计风景线 (树形DP)
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9164026.html
Copyright © 2011-2022 走看看