P5572 [CmdOI2019] 简单的数论题 题解
目录
题目描述
组数据,给定 ,求:
对 取模。
数据范围
- 。
时间限制 ,空间限制 。
分析
首先是一个二维求和时拆 关系的小技巧,一般来说,先枚举 再枚举 比先枚举 再枚举 有效得多。
具体到本题,如果先枚举 再枚举 :
后面的 没有很好的解决办法。
如果先枚举 再枚举 :
其中第一步利用了 的积性,最后一步枚举 是另一个常见技巧,并且:
要求 ,因此不同的 只有调和级数 项,可以预处理。
到这里遇到了一点瓶颈。二元组 有 项,内层虽然有 ,但由于 是关于 的变量,不能整除分块。
接下来的操作和 P4240 一模一样,考虑根号分治。
- 如果 ,二元组 只有 项,暴力枚举即可。
- 如果 ,则 。考虑对 预处理 ,整除分块即可做到 回答。
由 知 的状态数为:
可以接受。
时间复杂度 ,空间复杂度 。理论上取 ,可以得到最优的时间复杂度 。但是为了平衡空间复杂度,代码中取 。
#include<bits/stdc++.h>
using namespace std;
const int B=120,maxn=5e4+5,mod=23333;
int m,n,t,cas,res;
int p[maxn],mu[maxn],phi[maxn];
bitset<maxn> b;
vector<int> d[maxn],s[maxn],f[B+5][B+5];
void init(int n)
{
mu[1]=phi[1]=1;
for(int i=2,cnt=0;i<=n;i++)
{
if(!b[i]) p[++cnt]=i,mu[i]=-1,phi[i]=i-1;
for(int j=1;j<=cnt&&i*p[j]<=n;j++)
{
b[i*p[j]]=1;
if(i%p[j]==0)
{
phi[i*p[j]]=phi[i]*p[j];
break;
}
mu[i*p[j]]=-mu[i],phi[i*p[j]]=phi[i]*(p[j]-1);
}
}
for(int i=1;i<=n;i++)
{
s[i].resize(n/i+5);
for(int j=1;i*j<=n;j++) d[i*j].push_back(i),s[i][j]=s[i][j-1]+phi[i*j];
}
for(int i=1;i<=B;i++)
for(int j=1;j<=i;j++)
{
f[i][j].resize(n/i+5);
for(int k=1;k<=n/i;k++)
{
f[i][j][k]=f[i][j][k-1];
for(auto u:d[k]) f[i][j][k]=(f[i][j][k]+1ll*mu[u]*s[u][i]*s[u][j])%mod;
}
}
}
int main()
{
init(maxn-5);
for(scanf("%d",&cas);cas--;)
{
scanf("%d%d",&n,&m),res=0;
for(int t=1;t<=min(n/B,m);t++)
for(auto u:d[t])
res=(res+1ll*mu[u]*s[u][n/t]*s[u][m/t])%mod;
for(int l=n/B+1,r=0;l<=m;l=r+1)
{
r=min(n/(n/l),m/(m/l));
res=(res+f[n/l][m/l][r]-f[n/l][m/l][l-1])%mod;
}
printf("%d\n",(res+mod)%mod);
}
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/18569465
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】