• LOJ #6539 奇妙数论题


    不想咕太久..就随便找个题更一下

    LOJ#6539


    题意

    求题面里那个式子


    题解

    有一个常用的小式子

    $$sum_{x|a,x|b}varphi(x)=gcd(a,b)$$

    用这个式子直接对题面的式子进行化简

    $$
    egin{aligned}
    &sum_{i=1}^nsum_{j=1}^n(a_i,a_j)·(i,j)\
    &=sum_{i=1}^nsum_{j=1}^n(sum_{x|i,x|j}varphi(x))(a_i,a_j)\
    &=sum_{x=1}^nvarphi(x)sum_{x|i}sum_{x|j}(a_i,a_j)
    end{aligned}
    $$

    枚举x,相当于求一个大小为$ frac{n}{x}$的集合内两两$ gcd$的和

    再用一次最上面的式子优化

    $$
    egin{aligned}
    &sum_{i=1}^nsum_{j=1}^ngcd(a_i,a_j)\
    &=sum_{d=1}^nvarphi(d)(sum_{i=1}^n[d|a_i])^2
    end{aligned}
    $$

    预处理每个数的约数,每次暴力计算

    复杂度是对的..跑的飞快...


    代码

    小范围暴力抢了rk1

    #include<ctime>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #define rt register int
    #define ll long long
    using namespace std;
    inline ll read(){
        ll x=0;char zf=1;char ch=getchar();
        while(ch!='-'&&!isdigit(ch))ch=getchar();
        if(ch=='-')zf=-1,ch=getchar();
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();return x*zf;
    }
    void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);}
    void writeln(const ll y){write(y);putchar('
    ');}
    int k,m,n,x,y,z,cnt,ans;
    #define N 100000
    bool pri[N+10];int ss[N+10],phi[N+10];
    void init(){
        phi[1]=1;
        for(rt i=2;i<=N;i++){
            if(!pri[i]) ss[++cnt]=i,phi[i]=i-1;
            for(rt j=1;j<=cnt&&i*ss[j]<=N;j++){
                phi[i*ss[j]]=phi[i]*phi[ss[j]];
                pri[i*ss[j]]=1;
                if(i%ss[j]==0){
                    phi[i*ss[j]]=phi[i]*ss[j];
                    break;
                }
            }
        }
    }
    int a[100010],sum[100010];
    vector<int>ys[100010];
    ll calc2(int x){
        ll ret=0;
        for(rt i=x;i<=n;i+=x)sum[a[i]]++;
        for(rt i=1;i<=n;i++){
            int now=0;
            for(rt j=i;j<=n;j+=i)now+=sum[j];
            ret+=1ll*phi[i]*now*now;
        }
        for(rt i=x;i<=n;i+=x)sum[a[i]]=0;
        return ret;
    }
    ll calc(int x){
        ll ret=0;
        for(rt i=x;i<=n;i+=x){
            for(auto j:ys[a[i]]){
                ret+=(sum[j]*2+1)*phi[j];
                sum[j]++;
            }
        }
        for(rt i=x;i<=n;i+=x){
            for(auto j:ys[a[i]])sum[j]=0;
        }    
        return ret;
    }
    int main(){
        init();n=read();
        for(rt i=1;i<=n;i++)a[i]=read();
        for(rt i=1;i<=n;i++)
        for(rt j=i;j<=n;j+=i)ys[j].push_back(i);
        ll ans=0;
        for(rt x=1;x<=n;x++){
            if(x<=10)ans+=1ll*phi[x]*calc2(x);else 
            ans+=1ll*phi[x]*calc(x);
        }
        cout<<ans%1000000007;
        return 0;
    }
  • 相关阅读:
    NOIP2018 模拟赛(二十二)雅礼NOI
    浅谈左偏树在OI中的应用
    HDU3062&&HDU1814
    2-SAT超入门讲解
    bitset常用用法&&简单题分析
    NOIp2014提高组初赛错题简析
    2018十月刷题列表
    BZOJ 4804: 欧拉心算
    Luogu P2568 GCD
    Luogu P4137 Rmq Problem / mex
  • 原文地址:https://www.cnblogs.com/DreamlessDreams/p/10650992.html
Copyright © 2020-2023  润新知