首页 > 其他分享 >P3911 最小公倍数之和

P3911 最小公倍数之和

时间:2024-09-11 15:25:02浏览次数:13  
标签:10 ch 公倍数 sum 最小 mu int P3911 quad

原题链接

《一道思维题(小trick)》

\[ans=\sum _{i=1}^{n} \sum _{j=1}^{n}lcm(a_i,a_j) \]

当然正常莫反不能是这种形式的,可以观察到 \(a_i\) 的值域很小,只有 \(5\times 10^4\) ,所以我们去考虑直接枚举。

$\quad $ 记 \(c_{a_i}\) 为 \(a_i\) 在序列中出现的个数, \(N\) 为 \(a_i\) 的最大值,那么:

\begin{aligned}
ans&=\sum _{i=1}^{N}\sum _{j=1}^{N}lcm(i,j)*c_i *c_j\\
&=\sum _{d=1}^{N}d \sum _{i=1}^{\lfloor \frac{N}{d} \rfloor}\sum _{j=1}^{\lfloor \frac{N}{d} \rfloor} c _{id} *c _{jd} * i * j \sum _{k|gcd(i,j)}\mu (k)\\
&=\sum _{d=1}^{N}d\sum _{k=1}^{\lfloor \frac{N}{d} \lfloor}\mu(k)k ^2 \sum _{i=1}^{\lfloor \frac{N}{kd} \rfloor}\sum _{j=1}^{\lfloor \frac{N}{kd}\rfloor}c _{ikd} *c _{jkd}\\
&=\sum _{T=1}^{N}T\sum _{d|T}{\mu(d) d}(\sum _{i=1}^{\lfloor\frac{N}{T}\rfloor}c _{iT})^2
\end{aligned}

$\quad $ 然后中间那部分直接筛即可,后面那个括号直接暴力统计。

点击查看代码
#define yhl 0
#include<bits/stdc++.h>
using namespace std;
#define int __int128
const int N=5e4;
int n,prime[N+10],tot,mu[N+10],cnt[N+10],f[N+10],ans;
bool vis[N+10];
int read(){
    int ans=yhl;char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
void print(int x){
    if(x>9)print(x/10);
    putchar(x%10|48);
}
void init(){
    vis[1]=1;mu[1]=1;
    for(int i=2;i<=N;i++){
        if(!vis[i]){
            prime[++tot]=i;
            mu[i]=-1;
        }
        for(int j=1;j<=tot&&i*prime[j]<=N;j++){
            vis[i*prime[j]]=1;
            if(!(i%prime[j]))break;
            mu[i*prime[j]]=-mu[i];
        }
    }
    for(int i=1;i<=N;i++){
        for(int j=1;j*i<=N;j++){
            f[i*j]+=i*mu[i];
        }
    }
}
int get(int x){
    int op=N/x,ans=yhl;
    for(int i=1;i<=op;i++)ans+=i*cnt[i*x];
    return ans*ans;
}
signed main(){
    init();
    n=read();
    for(int i=1;i<=n;i++){
        int x=read();
        cnt[x]++;
    }
    for(int i=1;i<=N;i++)
        ans+=i*f[i]*get(i);
    print(ans);
    return yhl;
}

$\quad $ 这个码对于中间那部分的处理是 \(O(N ln N)\) 的,然后zcx问了我一下任意积性函数的筛法,发现确实不怎么会,《小探索了一下》,下面介绍一下。

$\quad $ 对于一个积性函数 \(f(x)\) ,我们知道:对于两个互质的整数 \(a\) 、\(b\) ,\(f(ab)=f(a)f(b)\) 。

$\quad $ 现在我们就知道了两个互质整数之积函数值的求法,然后我们还要知道 \(p \in prime\) 时,函数值的求法,这个很简单,直接代入即可,就不再介绍了。

$\quad $ 这里我们主要介绍 \(p \in prime\) 且 \(p|a\) 时 \(f(ap)\) 的求法,我们需要考虑多的这一个质数对我们的答案会有什么贡献,当然这个是要具体分析的,我拿上面那个函数举例:

\(f(x)=\sum _{d|x}d\mu(d)\)

$\quad $ 这时,一个 \(d\) 对该函数值有贡献,当且仅当 \(\mu(d)\) 不为零,思考一下我们发现,多了一个质数 \(p\),但是可以产生贡献的 \(d\) 实际上是没有发生变化的,后面的部分也不会发生变化。所以这个质数 \(p\) 此时没有多产生什么贡献。

$\quad $ 也就有:\(f(ap)=f(a)\) 。
然后我们就有了 \(O(n)\) 的筛法了。

点击查看代码
#define yhl 0
#include<bits/stdc++.h>
using namespace std;
#define int __int128
const int N=5e4;
int n,prime[N+10],tot,mu[N+10],cnt[N+10],f[N+10],ans;
bool vis[N+10];
int read(){
    int ans=yhl;char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
void print(int x){
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar(x%10|48);
}
void init(){
    vis[1]=1;f[1]=1;
    //不要忘了f(1)=1。
    for(int i=2;i<=N;i++){
        if(!vis[i]){
            prime[++tot]=i;
            f[i]=1-i;
        }
        for(int j=1;j<=tot&&i*prime[j]<=N;j++){
            vis[i*prime[j]]=1;
            if(!(i%prime[j])){f[i*prime[j]]=f[i];break;}
            f[i*prime[j]]=f[i]*f[prime[j]];
        }
    }
}
int get(int x){
    int op=N/x,ans=yhl;
    for(int i=1;i<=op;i++)ans+=i*cnt[i*x];
    return ans*ans;
}
signed main(){
    init();
    n=read();
    for(int i=1;i<=n;i++){
        int x=read();
        cnt[x]++;
    }
    for(int i=1;i<=N;i++)
        ans+=i*f[i]*get(i);
    print(ans);
    return yhl;
}

标签:10,ch,公倍数,sum,最小,mu,int,P3911,quad
From: https://www.cnblogs.com/0shadow0/p/18408310

相关文章

  • OpenCV结构分析与形状描述符(19)查找二维点集的最小面积外接旋转矩形函数minAreaRect()
    操作系统:ubuntu22.04OpenCV版本:OpenCV4.9IDE:VisualStudioCode编程语言:C++11算法描述找到一个包围输入的二维点集的最小面积旋转矩形。该函数计算并返回指定点集的最小面积边界矩形(可能是旋转的)。开发者需要注意的是,当数据接近包含的Mat元素边界时,返回的Rotated......
  • OpenCV结构分析与形状描述符(20)计算一个包围给定点集的最小外接圆函数minEnclosingCirc
    操作系统:ubuntu22.04OpenCV版本:OpenCV4.9IDE:VisualStudioCode编程语言:C++11算法描述找到一个包围二维点集的最小面积的圆。该函数使用迭代算法来寻找一个二维点集的最小外接圆。这意味着函数将会通过反复逼近的过程来计算出能够包围所有给定点且面积最小的圆。mi......
  • 图与网络——最小树问题精解
    最小生成树(MinimumSpanningTree,MST)问题是图论中的一个重要问题,其核心思想是:给定一个无向加权图(每条边具有权重值),通过选择若干边构建一棵包含所有顶点的生成树,并确保这些边的权重总和最小。最小生成树不仅保持了生成树的连通性和无圈性,还要求总权重最小化。在实际应用中,最小生......
  • 209. 长度最小的子数组
    滑动窗口!! classSolution{public:intminSubArrayLen(inttarget,vector<int>&nums){intleft=0,right=0,sum=nums[0];intminLength=INT_MAX;while(left<=right&&right<nums.size()){......
  • PCB零基础设计之GD32F103最小系统板(二)
    一.何为最小系统?    首先我们需要思考,什么是最小系统?最小系统板就是一个最精简的电路,精简到只能维持MCU的最基本的正常工作。接着我们就是继续提出一下问题,如最小系统包括哪些模块?为什么这些模块是必要的?如何设计这些模块?         关于最小系统板,我们想到的......
  • 提升系统安全性,从反射API和最小权限原则开始
    在当今的软件开发中,安全性已成为设计和实施中的首要考量。随着网络攻击手段的日益复杂,强化安全基线变得尤为重要。反射API(ApplicationProgrammingInterface)和最小权限原则是两个关键概念,它们在提升系统安全性方面起着至关重要的作用。一、反射API:动态调用的艺术反射API允许程......
  • 1170. 比较字符串最小字母出现频次
    题目链接1170.比较字符串最小字母出现频次思路题意不易理解;排序+二分(upper_bound)题解链接Python简洁解法关键点预先处理words时间复杂度\(O((n+m)p)\)空间复杂度\(O(1)\)代码实现:classSolution:defnumSmallerByFrequency(self,queries:L......
  • 744. 寻找比目标字母大的最小字母
    题目链接744.寻找比目标字母大的最小字母思路二分法题解链接官方题解关键点循环不变量(开区间):letters[left]<target&&letters[right]>=target时间复杂度\(O(\logn)\)空间复杂度\(O(1)\)代码实现:classSolution:defnextGreatestLetter......
  • 【算法笔记】Kruskal/Prim算法——求解最小生成树问题
    前言生活中经常遇到类似这种的问题:公路修建有一些城市,城市之间要修建高速公路,每两个城市之间都可以修双向的路。其中每两个城市之间修路都需要花费对应的金额。请问如何修路,使得总花费的金额最少,且任意两个城市之间都可以直接或间接通过修建的路来通行?实际上,我们可以把这种......
  • 最小二乘回归算法原理及Python实践
    最小二乘回归算法原理主要基于最小化误差平方和的思想,以找到数据的最佳函数匹配。以下是对其原理的详细阐述:一、基本原理最小二乘法(LeastSquaresMethod,简称LS)是一种数学优化技术,它通过最小化误差的平方和来寻找数据的最佳函数匹配。在回归分析中,最小二乘法被广泛应用于......