[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 题意 给出一棵树,每条边上有一个字符,字符集大小只 ...
随机推荐
- logging日志
import logging logging.basicConfig(filename='log.log', format='%(asctime)s - %(name)s - %(levelname) ...
- [Android]上传到多个Maven仓库的Gradle插件RapidMavenPushPlugin
博客搬迁至https://blog.wangjiegulu.com RSS订阅:https://blog.wangjiegulu.com/feed.xml RapidMavenPushPlugin 用 ...
- nyoj 星期几?
星期几? 时间限制:500 ms | 内存限制:65535 KB 难度:2 描述 Acmer 小鱼儿 埋头ku算一道题 条件:已知给定 一日期 告诉你 ...
- Crontab定时备份数据库
1.创建一个shell脚本文件 cd /usr mkdir dbbackup cd /usr/dbbackup vim backup.sh echo "------------------- ...
- java程序员最不愿意看到的十件事
0.遍历结果集并构造对象如果你是个时髦的开发者而不是专业人员,显然你从某篇博客中读过有开发者遇到Hibernate的“性能问题”,因而认为ORM都不好,觉得手动编码“明显更好”.喜欢的话你当然可以用 ...
- MySQL8.0 原子DDL
Edit MySQL8.0 原子DDL 简介 MySQL8.0 开始支持原子 DDL(atomic DDL),数据字典的更新,存储引擎操作,写二进制日志结合成了一个事务.在没有原子DDL之前,DROP ...
- windows计划任务
前段时间写了一个小工具,实现两个数据库的数据同步. 需求:要求每天的某个时间自动同步数据 功能写好之后,发现了windows一个自带的功能不错,可以实现我的需要,不用写定时器触发了 控制面板-> ...
- less规范
Less 编码规范 (1.1) 简介 该文档主要的设计目标是提高 Less 文档的团队一致性与可维护性. Less 代码的基本规范和原则与 CSS 编码规范 保持一致. 编撰 吕俊涛 本文档由商业运营 ...
- android 加速度传感器 ---摇一摇
package com.eboy.testyaoyiyao;import java.text.SimpleDateFormat;import java.util.Date;import android ...
- Python基础--函数的嵌套和闭包
一.名称空间和作用域 名称空间:Python所有有关命名的操作都是在操作名称空间,例如变量名,函数名 1.内置名称空间:Python解释器提供好的功能,解释器启动跟着一起启动,是全局作用域 2.全局名 ...