• 51nod


    https://www.51nod.com/Challenge/Problem.html#!#problemId=1363
    (sumlimits_{i=1}^{n}lcm(i,n))


    先换成gcd:
    (sumlimits_{i=1}^{n}frac{i*n}{gcd(i,n)})

    显而易见,枚举g:
    $ n * sumlimits_{g|n} frac{1}{g} sumlimits_{i=1}^{n} i*[gcd(i,n)==g] $

    提g,没有下整符号:
    $ n * sumlimits_{g|n} frac{1}{g} * g sumlimits_{i=1}^{frac{n}{g}} i*[gcd(i,frac{n}{g})==1] $


    考虑子问题:
    $sumlimits_{i=1}^{n} i*[gcd(i,n)==1] $

    也就是n以内和n互质的数的和。
    显然可以枚举因数d把他们减掉:
    $sumlimits_{i=1}^{n} i + sumlimits_{d|n,d!=1}mu(d)(d+2d+3d+...+n) $

    显然前面那堆等于 (d==1) 的结果。
    $sumlimits_{d|n}mu(d)(d+2d+3d+...+n) $

    比如求36的互质数的和时,6在枚举2和枚举3的时候算重,要加回去,4在枚举2的时候算过,不用算。
    化简:
    $ sumlimits_{d|n}mu(d)d(1+2+3+...+frac{n}{d}) ( )sumlimits_{d|n}mu(d)dfrac{(1+frac{n}{d})*frac{n}{d}}{2} $

    即:
    $frac{n}{2}sumlimits_{d|n}mu(d)(1+frac{n}{d}) ( 里面分配率: )frac{n}{2}(sumlimits_{d|n}mu(d)+sumlimits_{d|n}mu(d)frac{n}{d}) $

    然后一换:
    (frac{n}{2}([n==1]+varphi(n) ))

    求这个东西的复杂度很显然,预处理因子的欧拉函数是根号的,求单个n的欧拉函数也是根号的,所以整个式子就是根号的。

    记这个子问题为 (p(n)=sumlimits_{i=1}^{n} i*[gcd(i,n)==1] = frac{n}{2}([n==1]+varphi(n) )),求解它的复杂度就来源于欧拉函数


    回到$ n * sumlimits_{g|n} p(frac{n}{g}) $

    非常明显根号以内的欧拉函数可以重复利用,然后单独求一个最大的。

    总体复杂度是根号的。理论上根号是过不了的,1.7e8左右,但是看别人搞什么质因数分解?这个不也是最坏根号的吗?我觉得他们能行我也能行。

    果断T了,质因数分解假如遇到合数应该是跑得比我这快得多的。


    $ n * sumlimits_{g|n} p(frac{n}{g}) = frac{n}{2} (sumlimits_{g|n} gvarphi(g))+frac{n}{2}$

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    inline ll read() {
        ll x=0;
        char c=getchar();
        while(c<'0'||c>'9')
            c=getchar();
        do {
            x=(x<<3)+(x<<1)+c-'0';
            c=getchar();
        } while(c>='0'&&c<='9');
        return x;
    }
    
    inline void write(ll x) {
        //printf("%lld
    ",x);
        if(x>9) {
            write(x/10);
        }
        putchar(x%10+'0');
        return;
    }
    
    const int MAXN=5e6;
    //有用的质数恰好有3402个
    const int mod=1e9+7;
    const int inv2=mod+1>>1;
    
    int pri[MAXN+1];
    int &pritop=pri[0];
    int phi[MAXN+1];
    
    void sieve(int n=MAXN) {
        phi[1]=1;
        for(int i=2; i<=n; i++) {
            if(!phi[i]) {
                pri[++pritop]=i;
                phi[i]=i-1;
            }
            for(int j=1; j<=pritop&&i*pri[j]<=n; j++) {
                int t=i*pri[j];
                if(i%pri[j]) {
                    phi[t]=phi[i]*phi[pri[j]];
                } else {
                    phi[t]=phi[i]*pri[j];
                    break;
                }
            }
        }
    }
    
    inline int get_phi_pk(int n,int p){
        int res=n-n/p;
        return res;
    }
    
    int get_phi(int n){
        int res=n;
        for(int i=1;i<=3402;i++){
            if(n%pri[i]==0){
                res=res/pri[i]*(pri[i]-1);
                while(n%pri[i]==0)
                    n/=pri[i];
            }
            if(n==1)
                return res;
        }
        res=res/n*(n-1);
        return res;
    }
    
    int p(int n){
        ll res=(n==1);
        if(n<=MAXN)
            res+=phi[n];
        else
            res+=get_phi(n);
        res=(1ll*n*res)>>1;
        if(res>=mod)
            res%=mod;
        //printf("p[%d]=%lld
    ",n,res);
        return res;
    }
    
    int fac[80][2];
    int ftop=1;
    int q(int n){
        int cn=n;
        ll res=1;
        for(int i=1;pri[i]*pri[i]<=n;i++){
            if(n%pri[i]==0){
                ll tmpsum=1;
                ll pk=1;
                fac[ftop][0]=pri[i];
                fac[ftop][1]=0;
                while(n%pri[i]==0){
                    pk*=pri[i];
                    if(pk>=MAXN)
                        tmpsum+=pk*get_phi_pk(pk,pri[i]);
                    else
                        tmpsum+=pk*phi[pk];
                    fac[ftop][1]++;
                    n/=pri[i];
                }
                tmpsum%=mod;
                res*=tmpsum;
                res%=mod;
            }
        }
        if(n!=1){
            ll tmpsum=1+1ll*n*(n-1);
            res*=tmpsum;
            res%=mod;
        }
        //printf("q[%d]=%lld
    ",cn,res);
        return res;
    }
    
    ll ans(int n){
        ll res=(q(n)+1);
        res*=n;
        res%=mod;
        res*=inv2;
        res%=mod;
        return res;
    }
    
    inline void solve() {
        sieve();
        int t=read();
        while(t--){
            int n=read();
            write(ans(n));
            putchar('
    ');
        }
    }
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in","r",stdin);
    #endif // Yinku
        solve();
        return 0;
    }
    

    上面这个有很多多余操作,比如我现在根本就不关心欧拉函数怎么求了,也没必要给他们初始化这么多了,把要用的质数筛出来就结束了。欧拉函数在pk位置的求法就是(varphi(p^k)=p^k-(p^k)/p=(p-1)varphi(p^{k-1}))

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    inline int read() {
        int x=0;
        char c=getchar();
        while(c<'0'||c>'9')
            c=getchar();
        do {
            x=(x<<3)+(x<<1)+c-'0';
            c=getchar();
        } while(c>='0'&&c<='9');
        return x;
    }
    
    inline void write(int x) {
        //printf("%lld
    ",x);
        if(x>9) {
            write(x/10);
        }
        putchar(x%10+'0');
        return;
    }
    
    const int MAXN=4e5;
    const int mod=1e9+7;
    const int inv2=mod+1>>1;
    
    int pri[MAXN+1];
    int &pritop=pri[0];
    int phi[MAXN+1];
    
    void sieve(int n=MAXN) {
        phi[1]=1;
        for(int i=2; i<=n; i++) {
            if(!phi[i]) {
                pri[++pritop]=i;
                phi[i]=i-1;
            }
            for(int j=1; j<=pritop&&i*pri[j]<=n; j++) {
                int t=i*pri[j];
                if(i%pri[j]) {
                    phi[t]=phi[i]*phi[pri[j]];
                } else {
                    phi[t]=phi[i]*pri[j];
                    break;
                }
            }
        }
    }
    
    int q(int n){
        int cn=n;
        ll res=1;
        for(int i=1;pri[i]*pri[i]<=n;i++){
            if(n%pri[i]==0){
                ll tmpsum=1;
                ll pk=1;
                while(n%pri[i]==0){
                    pk*=pri[i];
                    tmpsum+=pk*(pk-pk/pri[i]);
                    n/=pri[i];
                }
                if(tmpsum>=mod)
                    tmpsum%=mod;
                res*=tmpsum;
                if(res>=mod)
                    res%=mod;
            }
        }
        if(n!=1){
            ll tmpsum=1ll*n*(n-1)+1;
            res*=tmpsum;
            if(res>=mod)
                res%=mod;
            res%=mod;
        }
        //printf("q[%d]=%lld
    ",cn,res);
        return res;
    }
    
    int ans(int n){
        ll res=q(n)+1;
        res*=n;
        if(res>=mod)
            res%=mod;
        res*=inv2;
        if(res>=mod)
            res%=mod;
        return res;
    }
    
    inline void solve() {
        sieve();
        int t=read();
        while(t--){
            int n=read();
            write(ans(n));
            putchar('
    ');
        }
    }
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in","r",stdin);
    #endif // Yinku
        solve();
        return 0;
    }
    
  • 相关阅读:
    蓝桥网试题 java 基础练习 特殊的数字
    蓝桥网试题 java 基础练习 杨辉三角形
    蓝桥网试题 java 基础练习 查找整数
    蓝桥网试题 java 基础练习 数列特征
    蓝桥网试题 java 基础练习 字母图形
    蓝桥网试题 java 基础练习 01字串
    蓝桥网试题 java 基础练习 回文数
    蓝桥网试题 java 基础练习 特殊回文数
    Using text search in Web page with Sikuli
    each of which 用法
  • 原文地址:https://www.cnblogs.com/Yinku/p/10987912.html
Copyright © 2020-2023  润新知