[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 题意 给出一棵树,每条边上有一个字符,字符集大小只 ...
随机推荐
- python pip包管理
pip 是一个安装和管理 Python 包的工具 , 是 easy_install 的一个替换品.本文将详细说明 安装 pip 的方法和 使用 pip 的一些基本操作如安装.更新和卸载 python ...
- python性能分析--cProfile
Python标准库中提供了三种用来分析程序性能的模块,分别是cProfile, profile和hotshot,另外还有一个辅助模块stats.这些模块提供了对Python程序的确定性分析功能,同时也 ...
- Python 简单聊天室
#coding=utf-8 from socket import * from threading import Thread import time udpSocket = socket(AF_IN ...
- C++ 实现一个信号量
C++ 实现一个信号量 信号量有很多应用场景,事实上只要是生产者-消费者模型,一般都需要一个信号量来控制. POSIX接口是有PV信号量API的.但C++标准没有.下面是一个PV信号量的简单实现.有些 ...
- Android 自定义控件高度设置onMeasure方法
最近使用hellocharts需要表格横向显示,而activity需要竖屏显示,在旋转以后,默认宽度为不超过屏幕宽度,则一直无法显示全控件. 此时需要修改onMeasure方法,这个方法是用来控制控件 ...
- 1.6 dropout正则化
除了L2正则化,还有一个非常实用的正则化方法----dropout(随机失活),下面介绍其工作原理. 假设你在训练下图左边的这样的神经网络,它存在过拟合情况,这就是dropout所要处理的.我们复制这 ...
- 减小APK大小
本篇文章翻译自Reduce APK Size 用户通常不会去下载体积过大的应用程序,特别是当自己的设备连接的是 2G/3G 或者按字节付费的网络.这篇文章描述了如何缩减 APK 的体积大小,以使得更多 ...
- 在Windows环境中使用Nginx, Consul, Consul Template搭建负载均衡和服务发现服务
搭建负载均衡和服务发现服务的目的 随着网站业务的不断提升,单个服务器的性能越来越难满足客户的业务需求,所以很多情况下,需要使用多服务器实例和负载均衡器来满足业务需要. Nginx 什么是Nginx N ...
- Linux正则表达式总结【网络资源整理】
正则表达式的分类 1.基本的正则表达式(Basic Regular Expression 又叫Basic RegEx 简称BREs) 2.扩展的正则表达式(Extended Regular Expre ...
- bootstrap——bootstrap-table(1)
前言: 特地纪念一下,自己参加这份工作刚好满一年.依旧乐在其中 言归正传:之前小接触过bootstrap,只是之后用得少了就生疏了,恰好现在的工作使用到了它,就再拿出来认真研究一下. 过程: 一直以来 ...