Luogu P1447 [NOI2010]能量采集
Preface
最近反演题做多了看什么都想反演。这道题由于数据弱,解法多种多样,这里简单分析一下。
首先转化下题目就是对于一个点\((x,y)\),所消耗的能量就是\(2(\gcd(x,y)-1)+1=2\cdot\gcd(x,y)-1\)(小学奥数题)
所以求和就是求\(\sum_{i=1}^n\sum_{j=1}^m2\cdot\gcd(i,j)-1=2\cdot\sum_{i=1}^n\sum_{j=1}^m\gcd(i,j)-nm\),因此主要问题就变成了求解\(\sum_{i=1}^n\sum_{j=1}^m\gcd(i,j)\)(对于反演来说,容斥的话直接怎么暴力怎么来)
一.转化+递推+容斥法
首先转化问题,我们考虑每一个数当它作为其它两个数的\(\gcd\)时会产生多少贡献。
先把问题简单化,我们先求出一个数为其它两个数的约数的方案数\(f(i)\),显然小学生都知道\(f(i)=\lfloor\frac{n}{i} \rfloor\lfloor\frac{m}{i} \rfloor\)
但是可能\(f(i)\)会多算当\(i|j\)时\(j\)的贡献,因此我们需要减掉\(\sum_{i|j} f(j)\)
因此我们从大到小枚举并计算\(f(i)\)即可,结合调和级数的公式发现复杂度为\(O(n(\ln(n)+H_n))\)(\(H_n\)是欧拉常数)
CODE
#include<cstdio>
#define RI register int
using namespace std;
int n,m,lim; long long ans,f[100005];
inline int min(int a,int b)
{
return a<b?a:b;
}
int main()
{
scanf("%d%d",&n,&m); lim=min(n,m);
for (RI i=lim;i;--i)
{
f[i]=1LL*(n/i)*(m/i);
for (RI j=i<<1;j<=lim;j+=i) f[i]-=f[j];
ans+=1LL*((i<<1LL)-1)*f[i];
}
return printf("%lld",ans),0;
}
二.我的蒟蒻反演做法
反演题做的多了就算是像我这样的蒟蒻也能自己推一推了。
感觉这个很套路就那以前的套路去套结果5min就搞出来一个看上去很正确的式子然后就过了。
这里讲一讲我的做法,根据之前做的一些反演题(如Luogu P2257 YY的GCD)我们很套路的来:
令\(f(d)\)为\(\gcd(i,j)(i\in[1,n],j\in[1,m])=d\)的个数,\(F(s)\)为\(d|\gcd(i,j)\)的个数
即:
\]
\]
考虑所求,则有:
\(ans=\sum_{d=1}^{\min(n,m)}f(d)\cdot d\)
还是用莫比乌斯反演定理,得到:
\]
把\(F(s)=\lfloor\frac{n}{s} \rfloor \lfloor\frac{m}{s} \rfloor\)代进去有:
\]
一个简单的套路,把枚举\(d\)变成\(n\)是\(d\)的多少倍,即:
\]
再把这个代回去就有:
\]
还要化简么?我们看看这道题的数据范围,\(n,m\le100000\),而且是单组询问
因此我们发现这个式子的复杂度根据调和级数定理为\(O(n(\ln(n)+H_n))\),因此暴力即可过
CODE
#include<cstdio>
#define RI register int
using namespace std;
const int P=100000;
int prime[P+5],cnt,phi[P+5],n,m,lim; bool vis[P+5]; long long ans,sum[P+5];
#define Pi prime[j]
inline void Euler(void)
{
vis[1]=phi[1]=1; RI i,j; for (i=2;i<=P;++i)
{
if (!vis[i]) prime[++cnt]=i,phi[i]=i-1;
for (RI j=1;j<=cnt&&i*Pi<=P;++j)
{
vis[i*Pi]=1; if (i%Pi) phi[i*Pi]=phi[i]*(Pi-1);
else { phi[i*Pi]=phi[i]*Pi; break; }
}
}
for (i=1;i<=P;++i) sum[i]=sum[i-1]+phi[i];
}
inline int min(int a,int b)
{
return a<b?a:b;
}
int main()
{
scanf("%d%d",&n,&m); Euler(); lim=min(n,m);
for (RI l=1,r;l<=lim;l=r+1)
{
r=min(n/(n/l),m/(m/l)); ans+=1LL*(n/l)*(m/l)*(sum[r]-sum[l-1]);
}
return printf("%lld",(ans<<1LL)-1LL*n*m),0;
}
三.利用狄利克雷卷积再加速
我们想一下,如果这题多组询问怎么办不保证毒瘤出题人不会出
因此我们思考应该还有更优秀的做法事实上也是有的
从第二种做法的\(f(d)=\sum_{d|s} \mu(\lfloor\frac{s}{d} \rfloor)\lfloor\frac{n}{s} \rfloor \lfloor\frac{m}{s} \rfloor\)开始,我们令\(T=ds\),则有:
\]
由于经典的狄利克雷卷积我们知道\(\mu\)的一个性质:\(\sum_{d|n}d\cdot\mu(\lfloor\frac{n}{d} \rfloor)=\phi(n)\)
(这个貌似也可以用欧拉函数的性质\(\sum_{d|n}\phi(d)=n\)再反演得来反正我不会证)
所以到现在就很简单了,把这个代进去就有:
\]
然后就是\(O(n)\)的式子了,当然,这个明显也可以做一发欧拉函数的前缀和结合除法分块做到单次询问\(O(\sqrt {\min(n,m))}\)的。因此多组询问也不再话下。
CODE
#include<cstdio>
#define RI register int
using namespace std;
const int P=100000;
int prime[P+5],cnt,phi[P+5],n,m,lim; bool vis[P+5]; long long ans,sum[P+5];
#define Pi prime[j]
inline void Euler(void)
{
vis[1]=phi[1]=1; RI i,j; for (i=2;i<=P;++i)
{
if (!vis[i]) prime[++cnt]=i,phi[i]=i-1;
for (RI j=1;j<=cnt&&i*Pi<=P;++j)
{
vis[i*Pi]=1; if (i%Pi) phi[i*Pi]=phi[i]*(Pi-1);
else { phi[i*Pi]=phi[i]*Pi; break; }
}
}
for (i=1;i<=P;++i) sum[i]=sum[i-1]+phi[i];
}
inline int min(int a,int b)
{
return a<b?a:b;
}
int main()
{
scanf("%d%d",&n,&m); Euler(); lim=min(n,m);
for (RI l=1,r;l<=lim;l=r+1)
{
r=min(n/(n/l),m/(m/l)); ans+=1LL*(n/l)*(m/l)*(sum[r]-sum[l-1]);
}
return printf("%lld",(ans<<1LL)-1LL*n*m),0;
}
Postscript
这真是一道很不错的数学题,上面的三种做法感觉都可以。
然而理论复杂度最优的算法三跑的和算法二一样。估计是除法做的太多常数偏大
而算法一就很优秀了,常数极小且不用欧拉筛的预处理,因此再速度上碾压了其它两种解法。
而且暴力不动脑的推导过程,啧啧称奇。
Luogu P1447 [NOI2010]能量采集的更多相关文章
- Luogu P1447 [NOI2010]能量采集 数论??欧拉
刚学的欧拉反演(在最后)就用上了,挺好$qwq$ 题意:求$\sum_{i=1}^{N}\sum_{j=1}^{M}(2*gcd(i,j)-1)$ 原式 $=2*\sum_{i=1}^{N}\sum_ ...
- luogu P1447 [NOI2010]能量采集 欧拉反演
题面 题目要我们求的东西可以化为: \[\sum_{i=1}^{n}\sum_{j=1}^{m}2*gcd(i,j)-1\] \[-nm+2\sum_{i=1}^{n}\sum_{j=1}^{m}gc ...
- 洛谷P1447 - [NOI2010]能量采集
Portal Description 给出\(n,m(n,m\leq10^5),\)计算\[ \sum_{i=1}^n \sum_{j=1}^m (2gcd(i,j)-1)\] Solution 简单 ...
- P1447 [NOI2010]能量采集
题目描述 栋栋有一块长方形的地,他在地上种了一种能量植物,这种植物可以采集太阳光的能量.在这些植物采集能量后,栋栋再使用一个能量汇集机器把这些植物采集到的能量汇集到一起. 栋栋的植物种得非常整齐,一共 ...
- 洛谷 P2158 [SDOI2008]仪仗队 && 洛谷 P1447 [NOI2010]能量采集
https://www.luogu.org/problemnew/show/P2158 以人所在位置为(0,0)建立坐标系, 显然除了(0,1)和(1,0)外,可以只在坐标(x,y)的gcd(x,y) ...
- 洛谷P1447 [NOI2010]能量采集(容斥)
传送门 很明显题目要求的东西可以写成$\sum_{i=1}^{n}\sum_{j=1}^m gcd(i,j)*2-1$(一点都不明显) 如果直接枚举肯定爆炸 那么我们设$f[i]$表示存在公因数$i$ ...
- 洛谷 P1447 [NOI2010]能量采集 (莫比乌斯反演)
题意:问题可以转化成求$\sum_{i=1}^{n}\sum_{j=1}^{m}(2*gcd(i,j)-1)$ 将2和-1提出来可以得到:$2*\sum_{i=1}^{n}\sum_{j=1}^{m} ...
- [NOI2010]能量采集(莫比乌斯反演)
题面: bzoj luogu NOI2010能量采集 题解 读完题之后我们发现在每个产生贡献的点\((x1,y1)\)中,它与原点之间的点\((x2,y2)\)都满足\(x2|x1\),\(y2|y1 ...
- BZOJ 2005: [Noi2010]能量采集
2005: [Noi2010]能量采集 Time Limit: 10 Sec Memory Limit: 552 MBSubmit: 3312 Solved: 1971[Submit][Statu ...
随机推荐
- Android spinner默认样式不支持换行和修改字体样式的解决方法
在spinner中显示的数据过多,需要换行,而Android自身提供的android.R.layout.simple_spinner_dropdown_item样式不支持换行,因此参考android提 ...
- 记录修改安卓5.0系统浏览器UI遇到的部分问题
碎碎念 今年七月份本科毕业后入职一家会议平板公司,经过一个一个多月的咸鱼培训轮岗生活,接手了几个小任务,本次记录一下其中一个任务:修改安卓5.0系统浏览器UI.刚接到任务的时候,本以为是很简单的一个任 ...
- scrapy系列(二)——startproject、genspider创建项目与模板使用
阅读本文之前需要安装scrapy,如果你还没有安装该框架,那么可以看之前一篇文章scrapy1.2windows安装. 现在默认大家都已经成功的安装了scrapy可以开始大展身手了.本文主要讲的是新建 ...
- 4.7 Sublime Text3 中配置 Python环境 --之上安装Sublime 3
返回总目录 目录: 1.展示效果: 2.缺优分析: 3.下载Sublime Text3 (一)展示效果: 1.能够交互式编写Python代码: 2.可以编写文件式Python代码: 3.能够自动补齐代 ...
- Linq2DB之研究和探索
1,对linq2db使用看法 最近在研究linq2db,用起来还不错,性能还不错的.之前也在博客园有些网友说用ado.net和depper写SQL语句,性能还要高.有时候牺牲点性能,为了提高开发效率, ...
- Orcale的NVL、NVL2函数和SQL Server的ISNULL函数
Orcal 的 nvl函数 NVL(Expr1,Expr2)如果Expr1为NULL,返回Expr2的值,否则返回Expr1的值,Expr1,Expr2都为NULL则返回NULL NVL2(Expr1 ...
- iOS时间显示今天昨天
一.前言 今天无意间想起写这个功能,仔细考虑了一下,其实很简单,整体思路如下: 先获取你所要转换的时间的年月日,然后再获取今天和昨天的年月日,然后对比,进而返回不同的字符串. 二.实现步骤 首先,我们 ...
- Deepin系统手动安装oracle jdk8详细教程
Deepin系统手动安装oracle jdk8详细教程 oracle官网下载jdk压缩包,使用 sudo tar -zxf jdk***解压文件,我放在在了home/diy/java/jdk路径下. ...
- 实现strStr()的golang实现
实现 strStr() 函数. 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始).如果不存在,则返 ...
- [经验总结] 在 windows 命令窗口中运行 python 脚本时提示 ModuleNotFoundError: No module named 'xxx'
先给出的代码和目录结构 获取CPU代码如下: # -*- coding:utf-8 -*- ''' Created on Sep 10, 2018 @author: ''' import sys im ...