zoukankan      html  css  js  c++  java
  • 杜教筛板子

    杜教筛核心公式

    $g(1)S(n)=sumlimits_{i=1}^n(f*g)(i)-sumlimits_{i=2}^n g(i)S(lfloor frac{n}{i} floor)$

    $S$是$f$的前缀和, $g$是构造的一个函数

    $g$需要满足$g$和$f*g$的前缀和可以$O(1)$求出

    $N$是最大范围, $N2$是$N^{2/3}$, $N3$是$N^{1/3}$.

    $N$范围超过$int$时要在$map$和$sum$里改成$ll$

    多组数据时, 只需要最开始调用一次init, 之后每组数据map不用清零

    const int N2 = 5e6+10;
    int cnt,f[N2],p[N2],vis[N2];
    map<int,int> S2;
    void init() {
        f[1] = 1;
        REP(i,2,N2-1) {
            if (!vis[i]) p[++cnt]=i,f[i] = ((ll)i*i-1)%P;
            for (int j=1,t;j<=cnt&&i*p[j]<N2; ++j) {
                vis[t=i*p[j]] = 1;
                if (i%p[j]==0) {f[t]=(ll)f[i]*p[j]%P*p[j]%P;break;}
                f[t] = (ll)f[i]*f[p[j]]%P;
            }
        }
    	REP(i,2,N2-1) f[i] = (f[i]+f[i-1])%P;
    }
    int g(int n) {return 1;}
    int sum_g(int n) {return n;}
    int sum_fg(int n) {return (ll)n*(n+1)%P*(2*n+1)%P*inv6%P;}
    
    int sum(int n) {
        if (n<N2) return f[n];
        if (S2.count(n)) return S2[n];
        int ans = sum_fg(n), mx = sqrt(n);
        REP(i,2,mx) ans=(ans-(ll)g(i)*sum(n/i))%P;
        for (int i=mx+1,j,k=n/i; i<=n; i=j+1,--k) {
            j = n/k;
            ans = (ans-(ll)(sum_g(j)-sum_g(i-1))*sum(k))%P;
        }
        return S2[n]=ans;
    }

    不用map的写法, 这样需要每组数据把$v$用时间戳清零.

    const int N2 = 5e6+10;
    const int N3 = 2510;
    int clk,cnt,f[N2],p[N2],vis[N2];
    int S2[N3], v[N3];
    void init() {
        f[1] = 1;
        REP(i,2,N2-1) {
            if (!vis[i]) p[++cnt]=i, f[i] = 1;
            for (int j=1,t;j<=cnt&&i*p[j]<N2; ++j) {
                vis[t=i*p[j]] = 1;
                if (i%p[j]==0) {f[t] = 1;break;}
                f[t] = (ll)f[i]*f[p[j]]%P;
            }
        }
    	REP(i,2,N2-1) f[i] = (f[i]+f[i-1])%P;
    }
    int sum(int n) {
        if (n<N2) return f[n];
    	int x = N/n;
    	if (v[x]==clk) return S2[x];
    	v[x] = clk;
    	int &ans = S2[x] = sum_fg(n), mx = sqrt(n);
        REP(i,2,mx) ans=(ans-(ll)g(i)*sum(n/i))%P;
        for (int i=mx+1,j,k=n/i; i<=n; i=j+1,--k) {
    		j = n/k;
    		ans = (ans-(ll)(sum_g(j)-sum_g(i-1))*sum(k))%P;
        }
    	if (ans<0) ans += P;
        return ans;
    }
    
  • 相关阅读:
    15 Django组件-中间件
    Android学习笔记-Dialog详解
    python爬取世界疫情信息到Mysql
    《构建之法》阅读笔记3
    团队项目--校园百晓生
    团队项目--校园百晓生
    php安装配置及问题解决
    《构建之法》阅读笔记2
    云服务器配置(转载)
    第五周总结
  • 原文地址:https://www.cnblogs.com/uid001/p/11447597.html
Copyright © 2011-2022 走看看