[Codeforces]871D Paths
失踪OJ回归。
毕竟这样的数论没做过几道,碰上一些具体的应用还是无所适从啊。小C还是借助这题大致摸索一下莫比乌斯函数吧。
Description
有n个点,标号为1~n,为这n个点建一张无向图。两个点x,y之间有连边当且仅当x,y不互质,求两两点对之间的最短路d(x,y)(1<=x<y<=n)之和。(如果两个点不连通,令它们之间的最短路为0)
Input
只有一行,一个正整数n。
Output
输出两两点对之间的最短路之和。
Sample Input
10
Sample Output
44
HINT
1<=n<=10^7。
Solution
通过仔细思考,1对答案没有贡献,我们不考虑1。设low[x]为x的最小质因数,我们可以把点对(x,y)之间的关系分为四种:
①gcd(x,y)>1:d(x,y)=1;
②gcd(x,y)=1且low[x]*low[y]<=n:d(x,y)=d(x,low[x]*low[y])+d(low[x]*low[y],y)=2;
③gcd(x,y)=1且low[x]*low[y]>n且low[x]*2<=n且low[y]*2<=n:d(x,y)=d(x,low[x]*2)+d(low[x]*2,low[y]*2)+d(low[y]*2,y)=3;
④gcd(x,y)=1且low[x]*2>n或low[y]*2>n:d(x,y)=0。
其中第一种和第四种都很好处理,第一种用欧拉函数,第四种求出每个数的最小质因数,统计一下low[x]>n/2的个数计算即可。
用所有方案数减去第一种和第四种的方案数就是第二和第三种的方案数和。
接下来的任务,就是求出第二种或第三种其中一种情况的方案数即可。第二种似乎看起来比第三种好求。
很自然地,我们想到对于每个low[x]统计x的个数。因此对于每个low[x]用二分或指针法加上前缀和就可以分别计算答案。
然而这个统计方法显然是有重复的。因为这样把gcd不为1的对数也算进去了,且每对这样的x,y恰好被算了一次。
所以现在我们要统计的是:gcd(x,y)>1且low[x]*low[y]<=n的x,y对数。
所以我们似乎可以枚举gcd(x,y),统计这样的x,y对数?但显然枚举gcd太难受了,枚举公因数还是更容易一些。
所以每对满足gcd(x,y)>1的x,y被算了 gcd(x,y)的因数个数 次!
怎么才能让每对满足x,y被算了 gcd(x,y)的因数个数 次后相当于只被算了一次呢?容斥?怎么容斥?
然后我们就想到了莫比乌斯反演中的
,
由于我们并没有考虑1,因此
,正好就是我们所想要求的啊!
所以现在我们求的是
。
我们枚举i,对于每个i考虑怎么计算x,y的对数。
当
时,low[x]*low[y]无论如何都不会大于n,所以这样的x,y对数为(n/i)*(n/i)。
当
时,low[x]*low[y]只有当x=y=i且i为质数的时候才会大于n,当满足这种情况时减去1即可。
所以我们就完成了这漫长的计算,时间复杂度O(n)。
#include <algorithm>
#include <cstring>
#include <cstdio>
#define ll long long
#define MN 10000005
using namespace std;
int n,prin,dys;
int zx[MN],pri[MN],phi[MN],miu[MN],sm[MN];
ll ans,sum; inline int read()
{
int n=,f=; char c=getchar();
while (c<'' || c>'') {if(c=='-')f=-; c=getchar();}
while (c>='' && c<='') {n=n*+c-''; c=getchar();}
return n*f;
} int main()
{
register int i,j;
n=read();
for (phi[]=miu[]=,i=;i<=n;++i)
{
if (!zx[i]) pri[++prin]=i,zx[i]=prin,phi[i]=i-,miu[i]=-;
for (j=;i*pri[j]<=n;++j)
{
zx[i*pri[j]]=j;
if (i%pri[j]==) {phi[i*pri[j]]=phi[i]*pri[j]; miu[i*pri[j]]=; break;}
else {phi[i*pri[j]]=phi[i]*(pri[j]-); miu[i*pri[j]]=-miu[i];}
}
ans+=i-phi[i]-; ++sm[zx[i]];
}
for (i=;i<=prin;++i) if (pri[i]*>n) ++dys;
ans+=(1LL*(n-)*(n-)/-ans-1LL*dys*(n-dys-)-1LL*dys*(dys-)/)*;
for (i=;i<=prin;++i) sm[i]+=sm[i-];
for (i=,j=prin;i<=prin;++i)
{
for (;j&&pri[i]*pri[j]>n;--j);
sum+=1LL*sm[j]*(sm[i]-sm[i-]);
}
for (i=;i<=n;++i) sum+=(1LL*(n/i)*(n/i)-(pri[zx[i]]==i&&1LL*i*i>n))*miu[i];
printf("%I64d",ans-sum/);
}
Last Word
这其中的计算思路还真是令人捉摸不透啊,各个计算之间的关联度很小,很显然需要很多碎片化的思路拼接起来才能完成这道题。
莫比乌斯函数其实就是通过枚举因数来进行的容斥吧。
[Codeforces]871D Paths的更多相关文章
- Codeforces.871D.Paths(莫比乌斯反演 根号分治)
题目链接 \(Description\) 给定\(n\),表示有一张\(n\)个点的无向图,两个点\(x,y\)之间有权值为\(1\)的边当且仅当\(\gcd(x,y)\neq1\).求\(1\sim ...
- Codeforces 871D Paths (欧拉函数 + 结论)
题目链接 Round #440 Div 1 Problem D 题意 把每个数看成一个点,如果$gcd(x, y) \neq 1$,则在$x$和$y$之间连一条长度为$1$的无向边. ...
- Codeforces 545E. Paths and Trees 最短路
E. Paths and Trees time limit per test: 3 seconds memory limit per test: 256 megabytes input: standa ...
- [Codeforces 545E] Paths and Trees
[题目链接] https://codeforces.com/contest/545/problem/E [算法] 首先求 u 到所有结点的最短路 记录每个节点最短路径上的最后一条边 答 ...
- codeforces 792D - Paths in a Complete Binary Tree
#include<cstdio> #include<iostream> #define lowbit(x) x&(-x) typedef long long ll; u ...
- Codeforces 545E. Paths and Trees[最短路+贪心]
[题目大意] 题目将从某点出发的所有最短路方案中,选择边权和最小的最短路方案,称为最短生成树. 题目要求一颗最短生成树,输出总边权和与选取边的编号.[题意分析] 比如下面的数据: 5 5 1 2 2 ...
- [codeforces 293]B. Distinct Paths
[codeforces 293]B. Distinct Paths 试题描述 You have a rectangular n × m-cell board. Some cells are alrea ...
- Codeforces Beta Round #14 (Div. 2) D. Two Paths 树形dp
D. Two Paths 题目连接: http://codeforces.com/contest/14/problem/D Description As you know, Bob's brother ...
- codeforces 741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(启发式合并)
codeforces 741D Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths 题意 给出一棵树,每条边上有一个字符,字符集大小只 ...
随机推荐
- 利用yield 实现Xrange功能
def xrange(n): start = 0 while True: if start>n: return yield start start+=1 obj = xrange(5) n1 = ...
- Oracle数据库游标精解
游标 定义:标识结果集中数据行的一种容器(CURSOR),游标允许应用程序对查询语句返回的行结果集中的每一行进行相同或不同的操作,而不是一次对整个结果集进行同一种操作.实际上是一种能从包括多条数据记录 ...
- js 防止重复点击
1.添加flag 适用于ajax 表单提交,提交之前flag = false , 提及中,true ,提交后false 2.事件重复点击: <script> var throttle = ...
- maven入门(1-3)maven的生命周期
maven的生命周期 maven的生命周期是抽象的,其实际行为都由插件来完成,引入maven 的 生命周期就是为了对所有的构建过程进行抽象和统一. 这种方式类似于模板方法,模板方法模式在父类中定义 ...
- C# 基于Bootstrap的三级联动
实现效果如图: 一.声明市.县.乡对应的下拉控件select <div class="form-group"> <label class="col-sm ...
- 用Jmeter实现SQLServer数据库的增删查改
1.添加线程组 Jmeter性能测试,最重要的就是线程组了,线程组相当于用户活动 2.添加JDBC Connection Configuration Database URL:jdbc:sqlserv ...
- Extensions in UWP Community Toolkit - SurfaceDialTextbox
概述 UWP Community Toolkit Extensions 中有一个为TextBox 提供的 SurfaceDial 扩展 - SurfaceDialTextbox,本篇我们结合代码详细讲 ...
- VS2013 堆栈溢出调查(0xC00000FD: Stack overflow)
在调试一个代码时,执行过程中会出现如下错误(0xC00000FD: Stack overflow). 很明显是堆栈溢出了. 网上很多方法,都是通过修改设置工程配置,把堆栈调大一些,如下图. 但是堆栈到 ...
- vue2.0项目引入element-ui
在项目中,为了方便我们工作和开发效率,常常引入一些框架来帮助我们完成高效的工作,今天我们就用vue来搭建一下框架,并且引入element-ui这个框架.安装流程也是我从失败中摸索到的,希望能帮助大家. ...
- POJ2398【判断点在直线哪一侧+二分查找区间】
题意:同POJ2318 #include<algorithm> #include<cstdio> #include<cstdlib> #include<cst ...