求
这种计数的题一般思想是枚举。
对于这道题,有一下几种做法,循序渐进
暴力:
就是暴力枚举所有数求,期望得分不清楚,大概
可以优化函数,记忆化一下。
画个矩阵发现可以只求下三角,即只求,将答案后再单独用等差数列求和公式处理对角线上的情况,一顿操作猛如虎,但因为会仍然无法通过
离正解只差一步的暴力:
枚举所有数,设组成数对的另一个数为,仍是只考虑的情况。设,则,符合这样的数的个数就应该是,所以枚举的所有因数为,。总复杂度。
肯定是稳过的,至此离正解只差一步。
正解
上面枚举因子显然是可以优化的,可以先枚举,再枚举另一个因子得出,和上面方法是等效的,调和级数总复杂度
int n,prime[maxn],pcnt,is_not_prime[maxn];
int phi[maxn];
ll ans;
void Get_Phi(int x)
{
is_not_prime[1]=1;
for(re int i=2;i<=x;++i)
{
if(!is_not_prime[i]) prime[++pcnt]=i,phi[i]=i-1;
for(re int j=1;j<=pcnt;++j)
{
if(i*prime[j]>x) break;
is_not_prime[i*prime[j]]=1;
if(!(i%prime[j]))
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
}
}
int vis[maxn];
int main()
{
n=read();
Get_Phi(n);
for(re int i=1;i<=n;++i)//枚举gcd
for(re int j=2;j*i<=n;++j)//枚举数对中较大的数/gcd的结果,从2枚举是为了不考虑对角线
{
ans+=(ll)phi[j]*i;
}
ans*=2;//上三角下三角
ans+=(ll)(1+n)*n/2;//统计对角线
printf("%lld\n",ans);
return 0;
}
当我在刷这道题的倍经验时,遇到了一道多组数据且的题,于是成功了
其实只需要对上面算法进行小的改动就行
ans+=(ll)phi[j]*i;
注意到这一行更新的其实是,相当于对的答案更新
那么可以这样写
f[i*j]+=(ll)phi[j]*i;
每个答案就是
所以对于数据个数很多的情况,预处理到最大范围,求前缀和,回答即可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现