• 模板


    好像在某些情况下杜教筛会遇到瓶颈,先看着。暑假学一些和队友交错的知识的同时开这个大坑。

    2019/7/30

    求一个前缀和 $sumlimits_{i=1}^n f(i) $ ,其中 (f(x)) 是积性函数,且 (f(p^k)) 是一个关于 (p) 的低次多项式。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define ll long long
    using namespace std;
    const ll MOD=1000000007,inv2=500000004,inv3=333333336;
    ll prime[1000005],num,sp1[1000005],sp2[1000005];
    ll n,Sqr,tot,g1[1000005],g2[1000005],w[1000005],ind1[1000005],ind2[1000005];
    bool flag[1000005];
    void pre(int n)//预处理,线性筛
    {
        flag[1]=1;
        for(int i=1;i<=n;i++)
        {
            if(!flag[i])
            {
                prime[++num]=i;
                sp1[num]=(sp1[num-1]+i)%MOD;
                sp2[num]=(sp2[num-1]+1ll*i*i)%MOD;
            }
            for(int j=1;j<=num&&prime[j]*i<=n;j++)
            {
                flag[i*prime[j]]=1;
                if(i%prime[j]==0)break;
            }
        }
    }
    ll S(ll x,int y)//第二部分
    {
        if(prime[y]>=x)return 0;
        ll k=x<=Sqr?ind1[x]:ind2[n/x];
        ll ans=(g2[k]-g1[k]+MOD-(sp2[y]-sp1[y])+MOD)%MOD;
        for(int i=y+1;i<=num&&prime[i]*prime[i]<=x;i++)
        {
            ll pe=prime[i];
            for(int e=1;pe<=x;e++,pe=pe*prime[i])
            {
                ll xx=pe%MOD;
                ans=(ans+xx*(xx-1)%MOD*(S(x/pe,i)+(e!=1)))%MOD;
            }
        }
        return ans%MOD;
    }
    int main()
    {
        scanf("%lld",&n);
        Sqr=sqrt(n);
        pre(Sqr);
        for(ll i=1;i<=n;)
        {
            ll j=n/(n/i);
            w[++tot]=n/i;
            g1[tot]=w[tot]%MOD;
            g2[tot]=g1[tot]*(g1[tot]+1)/2%MOD*(2*g1[tot]+1)%MOD*inv3%MOD;
            g2[tot]--;
            g1[tot]=g1[tot]*(g1[tot]+1)/2%MOD-1;
            if(n/i<=Sqr)ind1[n/i]=tot;
            else ind2[n/(n/i)]=tot;
            i=j+1;
        }//g1,g2分别表示一次项和二次项,ind1和ind2用来记录这个数在数组中的位置
        for(int i=1;i<=num;i++)//由于g数组可以滚动,所以就只开了一维
        {
            for(int j=1;j<=tot&&prime[i]*prime[i]<=w[j];j++)
            {
                ll k=w[j]/prime[i]<=Sqr?ind1[w[j]/prime[i]]:ind2[n/(w[j]/prime[i])];
                g1[j]-=prime[i]*(g1[k]-sp1[i-1]+MOD)%MOD;
                g2[j]-=prime[i]*prime[i]%MOD*(g2[k]-sp2[i-1]+MOD)%MOD;
                g1[j]%=MOD,g2[j]%=MOD;
                if(g1[j]<0)g1[j]+=MOD;
                if(g2[j]<0)g2[j]+=MOD;
            }
        }
        printf("%lld
    ",(S(n,0)+1)%MOD);
        return 0;
    }
    

    卡了一下常数,顺便卡了一下空间:不开启O2,预处理1跟n有关。
    3.54 s / 7.80 MB / 2.80 KB

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int MAXN = 100000 + 5; //MAXN = sqrt(MAXINPUTN)
    const ll MOD = 1000000007, inv2 = 500000004, inv3 = 333333336;
    
    int num;
    const int MAXP = 10000; //MAXN以内质数的数量,至多与MAXN一样大
    ll prime[MAXP], sp1[MAXP], sp2[MAXP];   //在调用init1()之后,可以精确计算出这里需要的大小
    
    int tot;
    const int DMAXN = (MAXN<<1) + 5; //整除分块需要的空间
    ll n, SQRT, g1[DMAXN], g2[DMAXN], w[DMAXN], ind1[DMAXN], ind2[DMAXN];
    
    void init1() {  //线性筛预处理
        SQRT = sqrt(n), num = 0 ;
        bitset < MAXN+5 > notprime;
        notprime[1] = 1;
        for(int i = 2; i <= SQRT; ++i) {
            if(!notprime[i]) {
                prime[++num] = i;
                sp1[num] = (sp1[num - 1] + i) % MOD;
                sp2[num] = (sp2[num - 1] + 1ll * i * i) % MOD;
                //spx[num] = 前num个质数的 x 次方和
            }
            for(int j = 1; j <= num && prime[j]*i <= SQRT; ++j) {
                notprime[i * prime[j]] = 1;
                if(i % prime[j] == 0)
                    break;
            }
        }
        printf("prime num=%d
    ", num);    //传入最大的n,算出num之后给MAXP赋值
    }
    
    void init2() {
        tot = 0;
        for(ll l = 1, r, t; l <= n; l = r + 1) {
            t = n / l, r = n / t;
            w[++tot] = t;
            g1[tot] = w[tot] % MOD;
            g2[tot] = (((g1[tot] * (g1[tot] + 1)) >> 1) % MOD * (2 * g1[tot] + 1) % MOD * inv3 % MOD) - 1;
            g1[tot] = ((g1[tot] * (g1[tot] + 1)) >> 1) % MOD - 1;
            if(t <= SQRT)
                ind1[t] = tot;
            else
                ind2[r] = tot;
        }
        //gx(n,j) 表示 [1,n]中,i是质数或者i的最小质因子>pj的数的 x 次方和,n滚动省略
        //ind1和ind2用来记录这个数在数组中的位置
        for(int i = 1; i <= num; i++) {
            for(int j = 1; j <= tot && prime[i]*prime[i] <= w[j]; j++) {
                ll k = w[j] / prime[i] <= SQRT ? ind1[w[j] / prime[i]] : ind2[n / (w[j] / prime[i])];
                g1[j] -= prime[i] * (g1[k] - sp1[i - 1] + MOD) % MOD;
                g2[j] -= prime[i] * prime[i] % MOD * (g2[k] - sp2[i - 1] + MOD) % MOD;
                g1[j] %= MOD, g2[j] %= MOD;
                if(g1[j] < 0)
                    g1[j] += MOD;
                if(g2[j] < 0)
                    g2[j] += MOD;
            }
        }
    }
    
    ll S(ll x, int y) {  //第二部分,不要记忆化,记忆化又慢又卡
        if(prime[y] >= x)
            return 0;
        int k = (x <= SQRT) ? ind1[x] : ind2[n / x];
        ll ans = (g2[k] - g1[k] + MOD - (sp2[y] - sp1[y]) + MOD) % MOD;
        for(int i = y + 1; i <= num && prime[i]*prime[i] <= x; i++) {
            ll pe = prime[i];
            for(int e = 1; pe <= x; ++e, pe = pe * prime[i]) {
                ll xx = pe % MOD;
                ans = (ans + xx * (xx - 1) % MOD * (S(x / pe, i) + (e != 1))) % MOD;
            }
        }
        return ans;
    }
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        scanf("%lld", &n);
        init1();
        init2();
        printf("%lld
    ", (S(n, 0) + 1) % MOD);  //加上f(1)
        return 0;
    }
    

    好像欧拉函数和莫比乌斯函数也是积性函数,然后在质数的幂次上也是容易求的多项式。
    (varphi(p^k)=p^k-p^{k-1}=p(p^{k-1}-1),k>=1)
    (mu(p)=-1,mu(p^k)=0,k>=2)

  • 相关阅读:
    Application package 'AndroidManifest.xml' must have a minimum of 2 segments.
    让“是男人就下到100层”在Android平台上跑起来
    移植一个cocos2d-x游戏
    cocos2d-x宏定义
    职场之需求
    cocos2d-x for android配置 & 运行 Sample on Linux OS
    input函数出现的问题(Python)
    职场之英语
    职场之随手记
    应用商店后台MIS的一些思考
  • 原文地址:https://www.cnblogs.com/Yinku/p/10964194.html
Copyright © 2020-2023  润新知