https://www.51nod.com/Challenge/Problem.html#!#problemId=1363

求\(\sum\limits_{i=1}^{n}lcm(i,n)\)


先换成gcd:

\(\sum\limits_{i=1}^{n}\frac{i*n}{gcd(i,n)}\)

显而易见,枚举g:

$ n * \sum\limits_{g|n} \frac{1}{g} \sum\limits_{i=1}^{n} i*[gcd(i,n)==g] $

提g,没有下整符号:

$ n * \sum\limits_{g|n} \frac{1}{g} * g \sum\limits_{i=1}^{\frac{n}{g}} i*[gcd(i,\frac{n}{g})==1] $


考虑子问题:

$\sum\limits_{i=1}^{n} i*[gcd(i,n)==1] $

也就是n以内和n互质的数的和。

显然可以枚举因数d把他们减掉:

$\sum\limits_{i=1}^{n} i + \sum\limits_{d|n,d!=1}\mu(d)(d+2d+3d+...+n) $

显然前面那堆等于 \(d==1\) 的结果。

$\sum\limits_{d|n}\mu(d)(d+2d+3d+...+n) $

比如求36的互质数的和时,6在枚举2和枚举3的时候算重,要加回去,4在枚举2的时候算过,不用算。

化简:

$ \sum\limits_{d|n}\mu(d)d(1+2+3+...+\frac{n}{d}) \(
\)\sum\limits_{d|n}\mu(d)d\frac{(1+\frac{n}{d})*\frac{n}{d}}{2} $

即:

$\frac{n}{2}\sum\limits_{d|n}\mu(d)(1+\frac{n}{d}) \(
里面分配率:
\)\frac{n}{2}(\sum\limits_{d|n}\mu(d)+\sum\limits_{d|n}\mu(d)\frac{n}{d}) $

然后一换:

\(\frac{n}{2}([n==1]+\varphi(n) )\)

求这个东西的复杂度很显然,预处理因子的欧拉函数是根号的,求单个n的欧拉函数也是根号的,所以整个式子就是根号的。

记这个子问题为 \(p(n)=\sum\limits_{i=1}^{n} i*[gcd(i,n)==1] = \frac{n}{2}([n==1]+\varphi(n) )\),求解它的复杂度就来源于欧拉函数


回到$ n * \sum\limits_{g|n} p(\frac{n}{g}) $

非常明显根号以内的欧拉函数可以重复利用,然后单独求一个最大的。

总体复杂度是根号的。理论上根号是过不了的,1.7e8左右,但是看别人搞什么质因数分解?这个不也是最坏根号的吗?我觉得他们能行我也能行。

果断T了,质因数分解假如遇到合数应该是跑得比我这快得多的。


$ n * \sum\limits_{g|n} p(\frac{n}{g}) = \frac{n}{2} (\sum\limits_{g|n} g\varphi(g))+\frac{n}{2}$

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; inline ll read() {
ll x=0;
char c=getchar();
while(c<'0'||c>'9')
c=getchar();
do {
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
} while(c>='0'&&c<='9');
return x;
} inline void write(ll x) {
//printf("%lld\n",x);
if(x>9) {
write(x/10);
}
putchar(x%10+'0');
return;
} const int MAXN=5e6;
//有用的质数恰好有3402个
const int mod=1e9+7;
const int inv2=mod+1>>1; int pri[MAXN+1];
int &pritop=pri[0];
int phi[MAXN+1]; void sieve(int n=MAXN) {
phi[1]=1;
for(int i=2; i<=n; i++) {
if(!phi[i]) {
pri[++pritop]=i;
phi[i]=i-1;
}
for(int j=1; j<=pritop&&i*pri[j]<=n; j++) {
int t=i*pri[j];
if(i%pri[j]) {
phi[t]=phi[i]*phi[pri[j]];
} else {
phi[t]=phi[i]*pri[j];
break;
}
}
}
} inline int get_phi_pk(int n,int p){
int res=n-n/p;
return res;
} int get_phi(int n){
int res=n;
for(int i=1;i<=3402;i++){
if(n%pri[i]==0){
res=res/pri[i]*(pri[i]-1);
while(n%pri[i]==0)
n/=pri[i];
}
if(n==1)
return res;
}
res=res/n*(n-1);
return res;
} int p(int n){
ll res=(n==1);
if(n<=MAXN)
res+=phi[n];
else
res+=get_phi(n);
res=(1ll*n*res)>>1;
if(res>=mod)
res%=mod;
//printf("p[%d]=%lld\n",n,res);
return res;
} int fac[80][2];
int ftop=1;
int q(int n){
int cn=n;
ll res=1;
for(int i=1;pri[i]*pri[i]<=n;i++){
if(n%pri[i]==0){
ll tmpsum=1;
ll pk=1;
fac[ftop][0]=pri[i];
fac[ftop][1]=0;
while(n%pri[i]==0){
pk*=pri[i];
if(pk>=MAXN)
tmpsum+=pk*get_phi_pk(pk,pri[i]);
else
tmpsum+=pk*phi[pk];
fac[ftop][1]++;
n/=pri[i];
}
tmpsum%=mod;
res*=tmpsum;
res%=mod;
}
}
if(n!=1){
ll tmpsum=1+1ll*n*(n-1);
res*=tmpsum;
res%=mod;
}
//printf("q[%d]=%lld\n",cn,res);
return res;
} ll ans(int n){
ll res=(q(n)+1);
res*=n;
res%=mod;
res*=inv2;
res%=mod;
return res;
} inline void solve() {
sieve();
int t=read();
while(t--){
int n=read();
write(ans(n));
putchar('\n');
}
} int main() {
#ifdef Yinku
freopen("Yinku.in","r",stdin);
#endif // Yinku
solve();
return 0;
}

上面这个有很多多余操作,比如我现在根本就不关心欧拉函数怎么求了,也没必要给他们初始化这么多了,把要用的质数筛出来就结束了。欧拉函数在pk位置的求法就是\(\varphi(p^k)=p^k-(p^k)/p=(p-1)\varphi(p^{k-1})\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; inline int read() {
int x=0;
char c=getchar();
while(c<'0'||c>'9')
c=getchar();
do {
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
} while(c>='0'&&c<='9');
return x;
} inline void write(int x) {
//printf("%lld\n",x);
if(x>9) {
write(x/10);
}
putchar(x%10+'0');
return;
} const int MAXN=4e5;
const int mod=1e9+7;
const int inv2=mod+1>>1; int pri[MAXN+1];
int &pritop=pri[0];
int phi[MAXN+1]; void sieve(int n=MAXN) {
phi[1]=1;
for(int i=2; i<=n; i++) {
if(!phi[i]) {
pri[++pritop]=i;
phi[i]=i-1;
}
for(int j=1; j<=pritop&&i*pri[j]<=n; j++) {
int t=i*pri[j];
if(i%pri[j]) {
phi[t]=phi[i]*phi[pri[j]];
} else {
phi[t]=phi[i]*pri[j];
break;
}
}
}
} int q(int n){
int cn=n;
ll res=1;
for(int i=1;pri[i]*pri[i]<=n;i++){
if(n%pri[i]==0){
ll tmpsum=1;
ll pk=1;
while(n%pri[i]==0){
pk*=pri[i];
tmpsum+=pk*(pk-pk/pri[i]);
n/=pri[i];
}
if(tmpsum>=mod)
tmpsum%=mod;
res*=tmpsum;
if(res>=mod)
res%=mod;
}
}
if(n!=1){
ll tmpsum=1ll*n*(n-1)+1;
res*=tmpsum;
if(res>=mod)
res%=mod;
res%=mod;
}
//printf("q[%d]=%lld\n",cn,res);
return res;
} int ans(int n){
ll res=q(n)+1;
res*=n;
if(res>=mod)
res%=mod;
res*=inv2;
if(res>=mod)
res%=mod;
return res;
} inline void solve() {
sieve();
int t=read();
while(t--){
int n=read();
write(ans(n));
putchar('\n');
}
} int main() {
#ifdef Yinku
freopen("Yinku.in","r",stdin);
#endif // Yinku
solve();
return 0;
}

51nod - 1363 - 最小公倍数之和 - 数论的更多相关文章

  1. 51nod 1363 最小公倍数之和 ——欧拉函数

    给出一个n,求1-n这n个数,同n的最小公倍数的和.例如:n = 6,1,2,3,4,5,6 同6的最小公倍数分别为6,6,6,12,30,6,加在一起 = 66. 由于结果很大,输出Mod 1000 ...

  2. 51nod 1238 最小公倍数之和 V3

    51nod 1238 最小公倍数之和 V3 求 \[ \sum_{i=1}^N\sum_{j=1}^N lcm(i,j) \] \(N\leq 10^{10}\) 先按照套路推一波反演的式子: \[ ...

  3. 51nod 1363 最小公倍数的和 欧拉函数+二进制枚举

    1363 最小公倍数之和 题目来源: SPOJ 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 160 给出一个n,求1-n这n个数,同n的最小公倍数的和.例如:n = 6,1,2,3 ...

  4. 51NOD 1238 最小公倍数之和 V3 [杜教筛]

    1238 最小公倍数之和 V3 三种做法!!! 见学习笔记,这里只贴代码 #include <iostream> #include <cstdio> #include < ...

  5. 51nod 1190 最小公倍数之和 V2

    给出2个数a, b,求LCM(a,b) + LCM(a+1,b) + .. + LCM(b,b). 例如:a = 1, b = 6,1,2,3,4,5,6 同6的最小公倍数分别为6,6,6,12,30 ...

  6. 51nod 1225 余数之和 数论

    1225 余数之和 题目连接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1225 Description F(n) ...

  7. 51nod 1238 最小公倍数之和 V3 【欧拉函数+杜教筛】

    首先题目中给出的代码打错了,少了个等于号,应该是 G=0; for(i=1;i<=N;i++) for(j=1;j<=N;j++) { G = (G + lcm(i,j)) % 10000 ...

  8. 51nod 1190 最小公倍数之和 V2【莫比乌斯反演】

    参考:http://blog.csdn.net/u014610830/article/details/49493279 这道题做起来感觉非常奇怪啊--头一次见把mu推出来再推没了的-- \[ \sum ...

  9. [51Nod 1238] 最小公倍数之和 (恶心杜教筛)

    题目描述 求∑i=1N∑j=1Nlcm(i,j)\sum_{i=1}^N\sum_{j=1}^Nlcm(i,j)i=1∑N​j=1∑N​lcm(i,j) 2<=N<=10102<=N ...

随机推荐

  1. 多媒体开发之--- Live555 server 获取不到本地ip 全为0

    今天把wis-streamer live555 移植到8148上面跑起来了,运行testOnDemandRTSPServer的时候发现,本地IP地址居然为0.0.0.0; 于是乎就跟踪调试了下,看看它 ...

  2. Netty 100万级高并发服务器配置

    前言 每一种该语言在某些极限情况下的表现一般都不太一样,那么我常用的Java语言,在达到100万个并发连接情况下,会怎么样呢,有些好奇,更有些期盼. 这次使用经常使用的顺手的netty NIO框架(n ...

  3. if UDP is permitted

    Networking Basics (The Java™ Tutorials > Custom Networking > Overview of Networking) https://d ...

  4. Perl 正则表达式语法

    1. 概要 Perl正则表达式是Boost.regex 默认行为,也可以将perl传入basic_regex 构造. boost::regex  e1(my_expression); boost::r ...

  5. 给第三方apk进行系统签名的几种方式【转】

    本文转载自:http://blog.csdn.net/luzhenrong45/article/details/47733053 版权声明:本文为博主原创文章,未经博主允许不得转载. -------- ...

  6. .net2.0 C# Json反序列化

    http://cjl20082002.blog.163.com/blog/static/120827332009511103457637/ 去:http://json.codeplex.com/下载  ...

  7. void类型和void *指针类型(网上摘抄总结)【转】

    http://www.blogjava.net/fhtdy2004/archive/2009/07/09/286004.html 现在在学linux编程过程中遇到很多void *指针类型,由于c很早学 ...

  8. mysql的navicat注册码生成

    首先下载安装Navicat在Navicat关闭的情况下运行注册机在注册机界面点击patch,选择Navicat安装目录下的Navicat.exe打补丁弹出破解成功后拔掉网线断网products选择my ...

  9. codevs 1012 最大公约数和最小公倍数问题

    题目描述 Description 输入二个正整数x0,y0(2<=x0<100000,2<=y0<=1000000),求出满足下列条件的P,Q的个数 条件:  1.P,Q是正整 ...

  10. Android Studio中的“favorites”和“bookmark”

    做项目难免来回查看某个文件的某个方法,某些文件可能访问率很高, 为了加快开发效率楼主推荐使用favorites (文件)bookmark (代码 行). favorites 的添加就在文件单击右键ad ...