• CF1575G GCD Festival


    \(\sum\sum gcd(i,j) \times gcd(a_i,a_j)\)

    考虑枚举这个 \(gcd(i,j)\)

    \(\sum_d \varphi(d)\sum_{i|d}\sum_{j|d} gcd(a_i,a_j)\)

    考虑后者等同于计算\(\sum_i\sum_j gcd(a_i,a_j)\)

    我们考虑枚举约数 \(d\),那么会 \(d | gcd\) 的情况为 \((\sum[d | a_i]) ^ 2\)

    考虑我们要求的是最大公约数,而非约数。

    但是我们有\(x = \sum_{d|x}\varphi(x)\)

    我们在情况数前加上一个系数即可。

    转而求
    \(\sum_d \varphi(d)\sum_t \varphi(t) (\sum[t | a_{k * d}]) ^ 2\)

    那么预处理出因数,我们枚举 \(d\) ,然后 \(O(nln)\) 的遍历 \(a_i\) ,然后一次 \(d(n)\) 的处理一个数。

    那么复杂度为预处理\(O(nln)\),计数复杂度\(O(\sum \lfloor\frac{n}{i} \rfloor d(i)) \leq O(Max{d(u)}nln)\)

    #include<iostream>
    #include<cstdio>
    #include<map>
    #include<vector>
    #include<queue>
    #define ll long long 
    #define N 100005
    #define mod ((ll)1e9 + 7)
    
    int n,a[N];
    int phi[N];
    int vis[N];
    int Cnt,pri[N];
    
    std::vector<int>Q[N];
    
    inline void sieve(){
    	phi[1] = 1;
    	for(int i = 2;i < N;++i){
    		if(!vis[i])
    		phi[i] = i - 1,pri[++Cnt] = i;
    		for(int j = 1;pri[j] * i < N && j <= Cnt;++j){
    			vis[i * pri[j]] = 1;
    			if(i % pri[j] == 0){
    				phi[i * pri[j]] = phi[i] * pri[j];
    				break;
    			}else{
    				phi[i * pri[j]] = phi[i] * (pri[j] - 1);
    			}
    		}	
    	}
    	for(int i = 1;i < N;++i)
    	for(int j = 1;j * i < N;++j)
    	Q[i * j].push_back(i);
    }
    
    ll ans = 0;
    
    int cnt[N];
    
    #define p(x) ((x >= mod) ? x - mod : x)
    
    inline void del(int u){
    //	std::cout<<u<<std::endl;
    	ll now = 0;
    	for(int i = u;i <= n;i += u){
    		for(int j = 0;j < Q[a[i]].size();++j){
    			now = p(now + p(p((p(cnt[Q[a[i]][j]] * 2) % mod + 1)) * phi[Q[a[i]][j]]) % mod);
    			cnt[Q[a[i]][j]] ++ ;
    		}
    	}
    	for(int i = u;i <= n;i += u){
    		for(int j = 0;j < Q[a[i]].size();++j){
    			cnt[Q[a[i]][j]] = 0 ;
    		}
    	}	
    	ans = p(ans + 1ll * phi[u] * p(now) % mod);
    }
    
    int main(){
    	sieve();
    	scanf("%d",&n);
    	for(int i = 1;i <= n;++i)
    	scanf("%d",&a[i]);
    	for(int i = 1;i <= n;++i)
    	del(i);
    	std::cout<<ans<<std::endl;
    }
    
  • 相关阅读:
    第十三周课程总结
    第十二周课程总结
    第十一周课程总结
    第十周课程总结
    第九周课程总结&实验报告(七)
    第八周课程总结&实验报告(六)
    第七周课程总结&实验报告(五)
    第六周课程总结&实验报告(四)
    第五周课程总结&试验报告(三)
    课程总结
  • 原文地址:https://www.cnblogs.com/dixiao/p/15609607.html
Copyright © 2020-2023  润新知