洛谷 P2398 GCD SUM || uva11417,uva11426,uva11424,洛谷P1390,洛谷P2257,洛谷P2568
https://www.luogu.org/problemnew/show/P2398
$原式=\sum_{k=1}^n(k\sum_{i=1}^n\sum_{j=1}^n[(i,j)=k])$
方法1:
发现暴力枚举k,就变成这道模板题
复杂度O(nlogn)
#pragma GCC optimize("Ofast")
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
#define N 2000000
ll prime[N+],len,mu[N+];
bool nprime[N+];
ll n,ans,a2;
ll F(ll x) {return (n/x)*(n/x);}
int main()
{
ll i,j,k;
mu[]=;
for(i=;i<=N;i++)
{
if(!nprime[i]) prime[++len]=i,mu[i]=-;
for(j=;j<=len&&i*prime[j]<=N;j++)
{
nprime[i*prime[j]]=;
if(i%prime[j]==) {mu[i*prime[j]]=;break;}
else mu[i*prime[j]]=-mu[i];
}
}
scanf("%lld",&n);
for(k=;k<=n;k++)
{
a2=;
for(i=;i<=n/k;i++)
a2+=mu[i]*F(i*k);
ans+=a2*k;
}
printf("%lld",ans);
return ;
}
方法2:
https://www.luogu.org/blog/Cinema/solution-p1390
(这是一道类似的题的题解)
复杂度好像是O(n)
具体地说,是嵌套整除分块,第一重枚举n/d,m/d,第二重枚举(n/d)/x,(m/d)/x
方法3:
$\sum_{i=1}^n\sum_{j=1}^n[(i,j)=k]=\sum_{i=1}^{{\lfloor}n/k{\rfloor}}\sum_{j=1}^{{\lfloor}n/k{\rfloor}}[(i,j)=1]$
$=2*(\sum_{i=1}^{{\lfloor}n/k{\rfloor}}\sum_{j=1}^{i}[(i,j)=1])-1=2*(\sum_{i=1}^{{\lfloor}n/k{\rfloor}}\varphi(i))-1$
这个欧拉函数的前缀和可以先预处理出来,然后枚举k
复杂度O(n)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
#define N 2000000
ll prime[N+],len,phi[N+];
ll d[N+];
bool nprime[N+];
ll n,ans;
ll F(ll x) {return (n/x)*(n/x);}
int main()
{
ll i,j,k;
phi[]=;
for(i=;i<=N;i++)
{
if(!nprime[i]) prime[++len]=i,phi[i]=i-;
for(j=;j<=len&&i*prime[j]<=N;j++)
{
nprime[i*prime[j]]=;
if(i%prime[j]==) {phi[i*prime[j]]=phi[i]*prime[j];break;}
else phi[i*prime[j]]=phi[i]*(prime[j]-);
}
}
for(i=;i<=N;i++) d[i]+=d[i-]+phi[i];
scanf("%lld",&n);
for(k=;k<=n;k++) ans+=k*(*d[n/k]-);
printf("%lld",ans);
return ;
}
方法4:
注意到方法3第35行的可以用整除分块优化,甚至可以O(n)预处理后每次O(sqrt(n))回答
类似的题(题面并不完全一样)
https://www.luogu.org/problemnew/show/UVA11417
https://www.luogu.org/problemnew/show/UVA11426
https://www.luogu.org/problemnew/show/P1390
https://www.luogu.org/problemnew/show/UVA11424
这题做法稍微有点不一样,因为数据组数多,不能直接每次O(n)回答
可以用方法4水过去
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
#define N 2000000
ll prime[N+],len,phi[N+];
ll d[N+];
bool nprime[N+];
ll n,ans;
ll F(ll x) {return (n/x)*(n/x);}
int main()
{
ll i,j,k;
phi[]=;
for(i=;i<=N;i++)
{
if(!nprime[i]) prime[++len]=i,phi[i]=i-;
for(j=;j<=len&&i*prime[j]<=N;j++)
{
nprime[i*prime[j]]=;
if(i%prime[j]==) {phi[i*prime[j]]=phi[i]*prime[j];break;}
else phi[i*prime[j]]=phi[i]*(prime[j]-);
}
}
for(i=;i<=N;i++) d[i]+=d[i-]+phi[i];
while(){
scanf("%lld",&n);
if(n==) break;
ans=;
for(i=;i<=n;i=j+)
{
j=min(n,n/(n/i));
ans+=(i+j)*(j-i+)/*(*d[n/i]-);
}
printf("%lld\n",(ans-(n+)*n/)/);}
return ;
}
或者:
设sum[x]=$\sum_{i=1}^{x-1}(i,x)$
那么询问为n时,答案就是$\sum_{i=1}^n{sum[i]}$
而sum[x]=$\sum_{k=1}^{x-1}(k*\sum_{i=1}^{x-1}[(i,x)=k])$
显然只有当k是x的因子且k不等于x时才能有贡献
枚举k,$\sum_{i=1}^{x-1}[(i,x)=k]=\sum_{i=1}^{\frac{x}{k}-1}[(i,\frac{x}{k})=1]$
$=(\sum_{i=1}^{\frac{x}{k}}[(i,\frac{x}{k})=1])=\phi(\frac{x}{k})$
可以看出来sum[x]=$(\sum_{d|x且d{\neq}x}(d*\phi(\frac{x}{d})))$
实际实现时可以把枚举因子变为枚举倍数
复杂度所有数据加起来O(nlogn+q)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
#define N 200000
ll prime[N+],len,phi[N+];
ll sum[N+];
bool nprime[N+];
ll n,ans[N+];
int main()
{
ll i,j,k;
phi[]=;
for(i=;i<=N;i++)
{
if(!nprime[i]) prime[++len]=i,phi[i]=i-;
for(j=;j<=len&&i*prime[j]<=N;j++)
{
nprime[i*prime[j]]=;
if(i%prime[j]==) {phi[i*prime[j]]=phi[i]*prime[j];break;}
else phi[i*prime[j]]=phi[i]*(prime[j]-);
}
}
for(i=;i<=N;i++)
for(j=*i;j<=N;j+=i)
sum[j]+=i*phi[j/i];
for(i=;i<=N;i++) ans[i]=ans[i-]+sum[i];
while(){
scanf("%lld",&n);
if(n==) break;
printf("%lld\n",ans[n]);
}
return ;
}
https://www.luogu.org/problemnew/show/P2257
事实上此题做法与以上几题是一样的,如果数据范围一样。。
然而此题有多组数据又是1e7,需要更好的做法
不妨设n<=m
根据方法2,得到答案是$\sum_{1<=k<=n且k为质数}\sum_{i=1}^n\mu(i){\lfloor}\frac{n}{ik}{\rfloor}{\lfloor}\frac{m}{ik}{\rfloor}$
好像不能化简了?然而A不了题?
强行解释一波推算方法:注意到最终的可能求法是整除分块,要枚举ik的积,那么试着把它提出来
第二种解释方法:为什么要这么写式子?学莫比乌斯反演时学来的式子枚举的就是d啊
看了题解,发现可以令d=ik
答案就等于$\sum_{1<=k<=n且k为质数}\sum_{k|d}\mu(\frac{d}{k}){\lfloor}\frac{n}{d}{\rfloor}{\lfloor}\frac{m}{d}{\rfloor}$
$=\sum_{d=1}^n\sum_{k|d且k为质数}\mu(\frac{d}{k}){\lfloor}\frac{n}{d}{\rfloor}{\lfloor}\frac{m}{d}{\rfloor}$
$\sum_{k|d且k为质数}\mu(\frac{d}{k})$可以预处理了,根据那个质数个数(近似)公式,预处理复杂度大概接近O(n)了。。
可以A了。。。
//#pragma GCC optimize("Ofast")
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
#define N 10000000
int prime[N+],len,mu[N+],dd[N+];
bool nprime[N+];
int n,m;ll ans;
int main()
{
int i,j,k,T,TT;
mu[]=;
for(i=;i<=N;i++)
{
if(!nprime[i]) prime[++len]=i,mu[i]=-;
for(j=;j<=len&&i*prime[j]<=N;j++)
{
nprime[i*prime[j]]=;
if(i%prime[j]==) {mu[i*prime[j]]=;break;}
else mu[i*prime[j]]=-mu[i];
}
}
for(i=;i<=len;i++)
for(j=,k=prime[i];j<=N/prime[i];j++,k+=prime[i])
dd[k]+=mu[j];
for(i=;i<=N;i++) dd[i]+=dd[i-];
scanf("%d",&T);
for(TT=;TT<=T;TT++)
{
scanf("%d%d",&n,&m);
if(n>m) swap(n,m);
ans=;
for(i=;i<=n;i=j+)
{
j=min(n,min(n/(n/i),m/(m/i)));
ans+=ll(dd[j]-dd[i-])*(n/i)*(m/i);
}
printf("%lld\n",ans);
}
return ;
}
双倍经验https://www.luogu.org/problemnew/show/P2568
好吧以上这题时限有点紧。。不过单次询问O(n)也可以用方法3或者方法2
洛谷 P2398 GCD SUM || uva11417,uva11426,uva11424,洛谷P1390,洛谷P2257,洛谷P2568的更多相关文章
- 洛谷P2398 GCD SUM (数学)
洛谷P2398 GCD SUM 题目描述 for i=1 to n for j=1 to n sum+=gcd(i,j) 给出n求sum. gcd(x,y)表示x,y的最大公约数. 输入输出格式 输入 ...
- 洛谷P2398 GCD SUM [数论,欧拉筛]
题目传送门 GCD SUM 题目描述 for i=1 to n for j=1 to n sum+=gcd(i,j) 给出n求sum. gcd(x,y)表示x,y的最大公约数. 输入输出格式 输入格式 ...
- 洛谷P2398 GCD SUM
题目描述 for i=1 to n for j=1 to n sum+=gcd(i,j) 给出n求sum. gcd(x,y)表示x,y的最大公约数. 输入输出格式 输入格式: n 输出格式: sum ...
- 洛谷 P2398 GCD SUM 题解
题面 挺有意思的. 设f[i]表示gcd(i,j)=i的个数,g[i]表示k|gcd(i,j)的个数; g[i]=(n/i)*(n/i); g[i]=f[i]+f[2i]+f[3i]+...; 所以f ...
- P2398 GCD SUM
P2398 GCD SUM一开始是憨打表,后来发现打多了,超过代码长度了.缩小之后是30分,和暴力一样.正解是,用f[k]表示gcd为k的一共有多少对.ans=sigma k(1->n) k*f ...
- *P2398 GCD SUM[数论]
题目描述 for i=1 to n for j=1 to n sum+=gcd(i,j) 解析 给出n求sum. gcd(x,y)表示x,y的最大公约数. 直接枚举复杂度为\(O(n^2)\),显然无 ...
- acdream 1148 GCD SUM 莫比乌斯反演 ansx,ansy
GCD SUM Time Limit: 8000/4000MS (Java/Others)Memory Limit: 128000/64000KB (Java/Others) SubmitStatis ...
- GCD SUM 强大的数论,容斥定理
GCD SUM Time Limit: 8000/4000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) SubmitStatu ...
- Luogu2398 GCD SUM
Luogu2398 GCD SUM 求 \(\displaystyle\sum_{i=1}^n\sum_{j=1}^n\gcd(i,j)\) \(n\leq10^5\) 数论 先常规化式子(大雾 \[ ...
随机推荐
- 三种方法打印 main函数的返回地址的值(old EIP)(用途,你懂得!)
这里能够简单的改动随意函数的返回地址.能够做到自己定义EIP的指向,就可以运行当前进程空间的随意指令,这里仅仅是让大家更清楚栈帧结构,没有涉及跨进程的inline HOOK 等,后面会陆续讲下读取随意 ...
- iOS优化策略
之前写的一系列文章或者小经验一直没有时间去整理放在博客上,今天整理出来,之前是写在作业部落,语法是markdown,点击链接浏览,仅供参考,希望对你有帮助. https://www.zybuluo.c ...
- C# 自定义控件及引用自动义控件
1.http://www.cnblogs.com/hjxzjp/p/7823292.html 优先考虑从现有的控件中进行派生,并添加所需要的功能. 在解决方案资源管理器窗口中设置:引用----&g ...
- 用redis实现动态时间段内统计排序
问题描述 需要根据某类数据在动态时间段内的统计值对这些数据进行排名.例如按过去24小时内点赞数排名的帖子,每隔一小时计算一次结果.以下描述均针对这个例子展开. 解决思路 针对这种问题,我的第一反应是直 ...
- 织梦文章分页后文章title的修改使得不一致
织梦Dedecms是一个不错的建站cms系统,最近在用织梦建站的时候发现文章分页后,每个分页都是同一个标题,不利于优化,想在分页后面加上一个数字来进行区别,怎么做呢? 找到include/arc.ar ...
- React引入,运行
1.引入 <script src="https://cdn.bootcss.com/react/15.5.4/react.min.js"></script> ...
- cassandra解析-log写
db/Keyspace.java 中的 apply 函数 中的 commitLogPosition = CommitLog.instance.add(mutation); 这一句确认是写log的代码. ...
- windows server2012之部署HTTPS安全站点
现在的互联网越来越重视网络安全方面的内容,像我们日常生活中浏览的网上银行网站等涉及安全的你都会发现有https 的标志出现,在URL前加https://前缀表明是用SSL加密的. 你的电脑与服务器之间 ...
- 书写优雅的shell脚本(六)- shell中的命令组合(&&、||、())
shell 在执行某个命令的时候,会返回一个返回值,该返回值保存在 shell 变量 $? 中.当 $? == 0 时,表示执行成功:当 $? == 1 时,表示执行失败. 有时候,下一条命令依赖前 ...
- codeforces 667D D. World Tour(最短路)
题目链接: D. World Tour time limit per test 5 seconds memory limit per test 512 megabytes input standard ...