• hdu 5901 Count primes


    题意:

    计数区间$[1, n](1 leq n leq 10^{11})$素数个数。

    分析:

    这里只介绍一种动态规划的做法。

    首先要说一下【分层思想】在动态规划中非常重要,下面的做法也正是基于这一思想。

    我们用$dp[i]$表示区间$[1, frac{n}{i}]$中素数的个数,用$c[i]$表示区间$[1, i]$中素数个数。

    那么我们要求的即是$dp[1]$。由于$n$最大是$10^{11}$,因此任何区间内合数的最小素因子不超过$sqrt{10^{11}}$。为了筛选素数,只需从区间内全体整数逐步划去最小素因子分别为$2, 3, 5, ...,$的和数即可。因此我们首先从小到大枚举素数$i$。

    把$dp[i]$和这样的一个集合对应起来:当枚举到素数$i$时,$dp[i]$对应集合$DP(i)$,$DP(i)$是区间$[1, frac{n}{i}]$划去所有包含不超过$i$的素因子的数后得到的集合,$dp[i]$为集合$DP(i)$的阶(长度)。考虑在加入素数$i$后更新$dp[j]$:

    $dp[j] := dp[j] - (dp[i * j] - c[i - 1]) (*)$

     注意到$DP(i * j)$和$DP(j)$的前面一部分是相同的,$DP(i * j)$即区间$[1, frac{n}{i * j}]$经划去所有包含小于$i$素因子合数后得到的集合,它当然包含所有小于$i$的素数。因此

    $dp[i * j] - c[i - 1]$中恰好包含了我们更新$dp[j]$时全部需要划去的元素,注意一点,这里$dp[i * j]$与$c[n / i / j]$与$c[n / (i * j)]$是等效的(因为$j$在内层循环逐增时,当且仅当$(i * j) | n$时对应到整数位置)。

    因为我们枚举最小素因子$i$,同时保证$n / i / j geq i - 1$因此控制外层循环$i leq sqrt{n} AND n / i / j geq i - 1$

    对于内层循环$j$,仅仅更新那些以后会用到的,这里保证在用到式 $(*)$时,$i * j leq sqrt{n}$, 因此$j leq sqrt{n}$

    当$i * j > sqrt{n}$时,使用式$dp[j] := dp[j] - (c[n / i / j] - c[i - 1])$替换上面的状态转移方程。

    为此可以保证$dp[]$和$c[]$空间均为$O(sqrt{n})$。

    再考虑对$c[]$的更新:

    $c[j] := c[j] - (c[j / i] - c[i - 1]) ext{ case }j / i geq i - 1$

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <queue>
    #include <map>
    #include <set>
    #include <stack>
    #include <ctime>
    #include <functional>
    #include <cmath>
    #include <iostream>
    #include <assert.h>
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define max(a, b) ((a) > (b) ? (a) : (b))
    #define min(a, b) ((a) < (b) ? (a) : (b))
    #define mp std :: make_pair
    #define st first
    #define nd second
    #define keyn (root->ch[1]->ch[0])
    #define lson (u << 1)
    #define rson (u << 1 | 1)
    #define pii std :: pair<int, int>
    #define pll pair<ll, ll>
    #define pb push_back
    #define type(x) __typeof(x.begin())
    #define foreach(i, j) for(type(j)i = j.begin(); i != j.end(); i++)
    #define FOR(i, s, t) for(int i = (s); i <= (t); i++)
    #define ROF(i, t, s) for(int i = (t); i >= (s); i--)
    #define dbg(x) std::cout << x << std::endl
    #define dbg2(x, y) std::cout << x << " " << y << std::endl
    #define clr(x, i) memset(x, (i), sizeof(x))
    #define maximize(x, y) x = max((x), (y))
    #define minimize(x, y) x = min((x), (y))
    using namespace std;
    typedef long long ll;
    const int int_inf = 0x3f3f3f3f;
    const ll ll_inf = 0x3f3f3f3f3f3f3f3f;
    const int INT_INF = (int)((1ll << 31) - 1);
    const double double_inf = 1e30;
    const double eps = 1e-14;
    typedef unsigned long long ul;
    typedef unsigned int ui;
    inline int readint() {
        int x;
        scanf("%d", &x);
        return x;
    }
    inline int readstr(char *s) {
        scanf("%s", s);
        return strlen(s);
    }
    
    class cmpt {
    public:
        bool operator () (const int &x, const int &y) const {
            return x > y;
        }
    };
    
    int Rand(int x, int o) {
        //if o set, return [1, x], else return [0, x - 1]
        if (!x) return 0;
        int tem = (int)((double)rand() / RAND_MAX * x) % x;
        return o ? tem + 1 : tem;
    }
    ll ll_rand(ll x, int o) {
        if (!x) return 0;
        ll tem = (ll)((double)rand() / RAND_MAX * x) % x;
        return o ? tem + 1 : tem;
    }
    
    void data_gen() {
        srand(time(0));
        freopen("in.txt", "w", stdout);
        int kases = 1;
        //printf("%d
    ", kases);
        while (kases--) {
            ll sz = 100000;
            printf("%d
    ", sz);
            FOR(i, 1, sz) {
                int o = Rand(2, 0);
                int O = Rand(26, 0);
                putchar(O + (o ? 'a' : 'A'));
            }
            putchar('
    ');
        }
    }
    
    const int maxn = 4e5 + 10;
    int c[maxn];
    ll dp[maxn];
    ll n;
    
    ll solve() {
        int mid = (int)sqrt(n + .5);
        FOR(i, 1, mid) dp[i] = n / i - 1, c[i] = i - 1;
        for (int i = 2; i <= mid; i++) {
            if (c[i] == c[i - 1]) continue;
            for (int j = 1; j <= mid && n / i / j >= i - 1; j++) {
                if (j <= mid / i) dp[j] -= dp[i * j] - c[i - 1];
                else dp[j] -= c[n / i / j] - c[i - 1];
            }
            ROF(j, mid, 1) {
                if (j / i < i - 1) break;
                c[j] -= c[j / i] - c[i - 1];
            }
        }
        return dp[1];
    }
    
    int main() {
        //data_gen(); return 0;
        //C(); return 0;
        int debug = 0;
        if (debug) freopen("in.txt", "r", stdin);
        //freopen("out.txt", "w", stdout);
        while (~scanf("%lld", &n)) {
            ll ans = solve();
            printf("%lld
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    QPS/TPS的预估
    tornado多进程模式不同进程写不同日志
    [python]pypy优化python性能
    [linux]查看进程占用内存
    [linux]杀死同一个应用的所有进程
    [LINUX] 快速回收连接
    jdbc批量写入
    Android 手机卫士--参照文档编写选择器
    Android 手机卫士--导航界面1的布局编写
    Android 手机卫士--设置界面&功能列表界面跳转逻辑处理
  • 原文地址:https://www.cnblogs.com/astoninfer/p/5901345.html
Copyright © 2020-2023  润新知