• LOJ6053 简单的函数(min_25筛)


    题目链接:LOJ

    题目大意:从前有个积性函数 $f$ 满足 $f(1)=1,f(p^k)=poplus k$。(异或)求其前 $n$ 项的和对 $10^9+7$ 取模的值。

    $1le nle 10^{10}$。


    这种奇怪但是简洁的积性函数求和,首选 min_25 筛。

    首先可以发现,对于质数 $p$,$pge 3$ 时 $f(p)=p-1$,$p=2$ 时 $f(p)=p+1$。

    所以可以先把 $f(2)$ 看做 $1$,这样方便处理 $g$,最后计算 $S$ 时再加个 $2$ 就好了。

    至于 min_25 筛的具体流程,打个广告

    时间复杂度 $O(frac{n^{3/4}}{log n})$。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=666666,mod=1000000007,inv2=500000004;
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    int sq,pri[maxn],pl,tot,id1[maxn],id2[maxn],g0[maxn],g1[maxn],s1[maxn];
    bool vis[maxn];
    ll n,w[maxn];
    inline int add(int a,int b){return a+b<mod?a+b:a+b-mod;}
    inline int sub(int a,int b){return a<b?a-b+mod:a-b;}
    inline int mul(int a,int b){return (ll)a*b%mod;}
    inline int id(ll x){return x<=sq?id1[x]:id2[n/x];}
    inline int pre1(ll x){return add(sub(g1[id(x)],g0[id(x)]),x>=2?2:0);}
    inline int pre2(ll x){return add(sub(s1[x],x),x?2:0);}
    void init(){
        sq=sqrt(n);
        FOR(i,2,sq){
            if(!vis[i]) pri[++pl]=i,s1[pl]=add(s1[pl-1],i);
            FOR(j,1,pl){
                if(i*pri[j]>sq) break;
                vis[i*pri[j]]=true;
                if(i%pri[j]==0) break;
            }
        }
        for(ll l=1,r;l<=n;l=r+1){
            r=n/(n/l);
            w[++tot]=n/l;
            if(n/l<=sq) id1[n/l]=tot;
            else id2[n/(n/l)]=tot;
            int x=w[tot]%mod;
            g0[tot]=sub(x,1);
            g1[tot]=sub(mul(mul(x,x+1),inv2),1);
        }
    }
    void calc_g(){
        FOR(i,1,pl) FOR(j,1,tot){
            if((ll)pri[i]*pri[i]>w[j]) break;
            g0[j]=sub(g0[j],sub(g0[id(w[j]/pri[i])],i-1));
            g1[j]=sub(g1[j],mul(pri[i],sub(g1[id(w[j]/pri[i])],s1[i-1])));
        }
    }
    int solve(ll nn,int x){
        if(pri[x]>=nn) return 0;
        int ans=sub(pre1(nn),pre2(x));
        FOR(i,x+1,pl){
            if((ll)pri[i]*pri[i]>nn) break;
            ll pro=1;
            FOR(j,1,50){
                pro*=pri[i];
                if(pro>nn) break;
                ans=add(ans,mul(pri[i]^j,add(j!=1,solve(nn/pro,i))));
            }
        }
        return ans;
    }
    int main(){
        scanf("%lld",&n);
        init();
        calc_g();
        printf("%d
    ",add(1,solve(n,0)));
    }
    View Code
  • 相关阅读:
    数字证书
    数字签名

    共享密钥加密
    公开密钥加密
    迪菲赫尔曼密钥交换
    线性查找
    深度优先搜索
    广度优先搜索
    混合加密
  • 原文地址:https://www.cnblogs.com/1000Suns/p/10800329.html
Copyright © 2020-2023  润新知