您的位置:首页 > 其它

BZOJ 2705 Longge的问题 (欧拉函数)

2017-08-11 21:27 302 查看

思路:

根据n的范围我们发现,就算是线性的扫一遍也不行(1e9的复杂度太高了)。

所以考虑一种logn或者sqrt(n)的方法;

我们知道这种题多半是不能按照题意直接做,而是要考虑每个gcd对答案的贡献。

考虑n的因子i,以i为gcd的对答案的贡献即为 gcd(某个数,n)==i 的个数乘以i。又因为这道题要算的gcd中有一个是固定值,所以我们可以考虑将之转化为欧拉函数,即,个数为Euler(n/i)。在这个区间里和n/i互质的数,在分别乘以i后,一定就满足 gcd(某个数,n)==i 。

同时,我们注意到每当我们找到n的一个因子i,我们其实同时还获得了n的另一个因子n/i,所以我们就可以通过这个,将复杂度降到sqrt(n)了。

注意,如果n是一个完全平方数,那么记得减去多加的那个因子的一遍贡献。

ps:

对了,这道题由于n太大了,只能每次求euler函数的值,而不能用线性筛o(n)的求。

#include<stdio.h>
#include <iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#define eps 1e-8
typedef long long int lli;
using namespace std;
const int maxn = 1e6+10;
lli euler(lli n){
lli res = n,x=n;;
for(lli i = 2;i*i <= x; i++){
if(x%i==0){
res = res/i * (i-1);
while(x%i==0){
x/=i;
}
}
}
if(x!=1){
res = res/x*(x-1);
}
return res;
}
int main(){
lli p,q;
lli a,b;
scanf("%lld",&a);
lli ans = 0;
for(lli i = 1;i*i <= a;i++){
if(a%i == 0){
ans += i*euler(a/i)+ a/i*euler(i);
if(i*i==a) ans-= a/i*euler(i);
}
}
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: