题目:
题目背景
-
致远星舰队旗舰——“养生壶”号上(别问为啥,外星人的语言习惯)
-
装着全致远星最先进的密码保护系统
-
你作为OI星最强的间谍——(代号:映山红)
-
偷偷来到了这艘战舰上
-
你经历重重历险终于来到了战舰的总控室
-
密码系统作为高级货当然不是静态的
-
它描绘的是这样一个问题:
-
计算满足:1到n内,gcd(x,y)为素数的数对有多少。
-
现在帝国的护卫队已经发现了你的踪迹
-
你能够使用的就是一台性能与公元$2000$年电脑性能几乎无差的掌上解码器
-
你需要在尽可能短的时间内算出问题的答案
题目描述
-
求1≤x,y≤n中 , 满足:gcd(x,y)为素数的数对有多少。
输入格式
-
一行一个数n
输出格式
-
一行一个数 , 表示满足条件的数对数量
输入输出样例
输入 #1
4
输出 #1
4
输入 #2
12
输出 #2
39
说明/提示
-
对于10%的数据,保证n≤10
-
对于50%的数据,保证n≤105
-
对于100% 的数据 , 保证n≤107
-
数据随机生成 ,
大佬们可以暴力踩标程(bushi)
翻译一下题意:给定一个正整数n,求1≤x,y≤n中满足gcd(x,y)为素数的数对有多少。
思路:
既然gcd(x,y)是一个质数,那么我们可以认为,如果我们假设gcd(x,y)的值为p,则gcd(x/p,y/p)的值一定为1。既然这样,那么我们就可以先求出1到n中所有的素数,然后再依次求出对于1到n/p[i]的x和y,满足gcd(x,y)=1的素数的个数。
我们在求对于每一对1≤x,y≤n/p[i]的x和y,满足gcd(x,y)=1的数对的对数时,不妨设x≤y(如果不满足则交换x和y的顺序)。
我们考虑对于每一个确定的y,因为x≤y,所以对于每一对1≤x,y≤n/p[i]的x和y,当我们给定一个确定的y值的时候,满足gcd(x,y)=1的数对的对数就等于φ(y)的值。
因而,对于每一对1≤x,y≤n/p[i]的x和y,满足gcd(x,y)=1的数对的对数就等于∑(i=1->n/p[i])φ(i)。
这样我们就可以得出这道题的完整思路:
我们先跑一遍筛素数(这里用线性筛即可),筛出1到n之间的所有质数,以及求出1到n之间每个数i的φ(i)的值,然后再枚举质数,求出对于1到n的每一个质数p[i],它所对应的∑(i=1->n/p[i])φ(i)的值,最后再一次进行累加求和。
1 #include<cstdio>
2 #define ll long long
3 using namespace std;
4
5 const ll N=1e7+9;
6 ll pr[N],ph[N];
7
8 int main()
9 {
10 register ll n,i,j,k=0,p;
11 register long long s=0,t=0;
12
13 scanf("%lld",&n);
14
15 ph[1]=1;
16 for(i=2;i<=n;++i)
17 {
18 if(!ph[i]) pr[++k]=i,ph[i]=i-1;
19 for(j=1;p=i*pr[j],p<=n&&j<=k;++j)
20 {
21 if(i%pr[j]==0)
22 {
23 ph[p]=ph[i]*pr[j];
24 break;
25 }
26 else ph[p]=ph[i]*ph[pr[j]];
27 }
28 }
29
30 for(i=1,j=k;j;--j)
31 {
32 for(p=n/pr[j];i<=p;++i)t+=ph[i];
33 s+=t;
34 }
35
36 printf("%lld",(s<<1)-k);
37 return 0;
38 }