[bzoj2226] LCMSum 数学+筛法
来源:互联网 发布:交行信用卡 知乎 编辑:程序博客网 时间:2024/06/05 07:07
题目链接:bzoj2226 .
—————————————-
概述
题目大意如下:
给定正整数
题目有多组数据。
—————————————-
分析
对于
对于某个
所以,我们不妨枚举
我们得到下式:
化到这里,问题就变成了:对于
那么关键来了,所有与
——————–
结论:∑i=1ni×[gcd(i,n)=1] = n×φ(n)2.
特别地,n=1 时值为1.
证明:
引理: 对于一个与
引理证明:设
我们要求的是与
根据引理,我们又有:
结论证毕。
——————–
有了这个结论就好办了,我们原来要求的是:
现在我们可以将它转化为:
其中,加
至此,有2种做法,一个是80分,一个是100分。
80分:
待求:
我们可以线性筛出所有的
代码
#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>#define ll long long#define For(i,j,k) for(register int i=j; i<=(int)k; ++i)#define Forr(i,j,k) for(register int i=j; i>=(int)k; --i)#define INF 0x3f3f3f3fusing namespace std;const int maxn = 1000000+5;int T, n, tot;int pri[maxn/5], phi[maxn];bool vis[maxn];inline void read(int &x){ x = 0; char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)) x = (x<<3)+(x<<1)+(c^48), c = getchar();}inline void init(){ phi[1] = 1; For(i, 2, maxn-1){ if(!vis[i]){ pri[++tot] = i; phi[i] = i-1; } for(int j=1,x; j<=tot&&(x=i*pri[j])<maxn; ++j){ vis[x] = true; if(i%pri[j] == 0){ phi[x] = phi[i]*pri[j]; break; } else phi[x] = phi[i]*(pri[j]-1); } }}inline ll calc(int n){ ll sum, back; sum = 1, back = 1ll * n; for(int i = 1; i*i<=n; ++i) if(n%i == 0){ sum += 1ll * phi[i] * i >> 1; if(i*i == n) break; sum += 1ll * phi[n/i] * (n/i) >> 1; } back *= sum; return back;}int main(){ init(); read(T); while(T --){ read(n); printf("%lld\n", calc(n)); } return 0;}
100分
待求:
我们令
我们观察一下
既然
设
那么我们接下来要解决的问题是
总共分2种情况:
gcd(a,p)=1 ,即a,p 互质。这种情况很好处理:h(a×p)=h(a)×h(p). gcd(a,p)≠1 .此时又分两种小情况:(1)
a=x×pr. 那么,h(a×p)=h(x)×h(pr+1). (2)
a=pr. 这种情况下要稍微推一下式子:已知:h(a)=h(pr)=1+∑i=1rpi×φ(pi). 我们对它进行进一步转化:
h(a)=1+∑i=1rpi×(pi−pi−1)=1+(p−1)∑i=1rp2i−1. 那么同理:
h(a×p)=h(pr+1)=1+(p−1)∑i=1r+1p2i−1. 对于
h(pr) ,我们可以发现如下的关系:h(pr)−1=(p−1)∑i=1rp2i−1
至此我们得到了
整理一下:
至此,线性筛筛出所有的
代码
#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>#define ll long long#define For(i,j,k) for(register ll i=j; i<=(ll)k; ++i)#define Forr(i,j,k) for(register ll i=j; i>=(ll)k; --i)#define INF 0x3f3f3f3fusing namespace std;const ll maxn = 1000000+5;ll T, n, tot;ll pri[maxn/5], phi[maxn];bool vis[maxn];inline void read(ll &x){ x = 0; char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)) x = (x<<3)+(x<<1)+(c^48), c = getchar();}inline void init(){ phi[1] = 1; For(i, 2, maxn-1){ if(!vis[i]){ pri[++tot] = i; phi[i] = (i-1) * i + 1; } for(ll j=1,x; j<=tot&&(x=i*pri[j])<maxn; ++j){ vis[x] = true; if(i%pri[j] == 0){ ll ii = i, jj = pri[j]; while(ii%pri[j] == 0){ ii /= pri[j]; jj *= pri[j]; } if(ii > 1) phi[x] = phi[ii] * phi[jj]; else phi[x] = phi[i] * pri[j]*pri[j] - pri[j]+1; break; } else phi[x] = phi[i]*phi[pri[j]]; } }}int main(){ init(); read(T); while(T --){ read(n); printf("%lld\n", 1ll * (phi[n]+1 >> 1) * n); } return 0;}
—————————————-
小结
这一题的解决关键在于中间那个欧拉函数的结论,利用那个结论可以把式子化成能够用数论函数解决的形式。之后的重点是推导
—————————————-
- [bzoj2226] LCMSum 数学+筛法
- bzoj2226 LCMSum
- 【bzoj2226】【spoj5971】【lcmsum】【数论】
- [bzoj2226][SPOJ5971]LCMSUM
- BZOJ2226: [Spoj 5971] LCMSum
- [BZOJ2226][Spoj5971][数论]LCMSum[好题]
- BZOJ2226
- bzoj 2226: [Spoj 5971] LCMSum 数学+欧拉函数
- spoj LCMSUM
- bzoj2226(数论)
- BZOJ2226 基础数论
- SPOJ LCMSUM (数论)
- SPOJ LCMSUM&GCDEX
- SPOJ LCMSUM (数论)
- [BZOJ 2226] LCMSum
- BZOJ 2226 Spoj 5971 LCMSum 数论
- BZOJ 2226 [Spoj 5971] LCMSum 数论
- bzoj2226(又是智商的突破,加油)
- GBDT和随机森林的区别
- Tensorflow之池化函数汇总
- LeetCode:526. Beautiful Arrangement
- es6 itaertor遍历器
- 继承性
- [bzoj2226] LCMSum 数学+筛法
- java进阶建议阅读的书籍
- python中对文件的操作总结
- Hibernate之查询
- IOS第三方库GPUImage的CameraDemo
- 安装CodeBlocks遇到未找到编译器的问题
- linux后台开发具备能力集锦
- elasticsearh插件runAsDouble里面获取不到枚举值
- 简单工厂模式