JZOJ 5163【NOIP2017模拟6.25】PS的烦恼

Description:

话说PS总是有着各种各样的烦恼,这天,他又在为自己失败的感情史烦恼着。这时,他心中的女神,魔法少女小圆从天而降,她对他说,如果你能帮我解决一个问题,我就让你永远没有烦恼。
问题是这样的:
寻找一个最大的k,使得存在一个x使得x^k=y,那么f(y)=k,即y最多可以开k次方根。
小圆的要求是求出从a到b的f值之和(包括a和b)。

Input:

多组数据,每组数据一行包含两个数a,b,文件以0 0(不需要输出)结尾。

Output:

每组数据一行表示这一段f值之和。

Sample Input:

2 10
248832 248832
0 0

Sample Output:

13
5

Data Constraint:

30%的数据满足:a<=1000 b<=1000
100%的数据满足:2<=a<=b<=10^18

题目大意:

x=pq
d(x)=gcd(q)
Ans=bi=af(i)

题解:

莫比乌斯反演。
f(d)=ni=2(d(i)==d)

g(d)=n/di=1f(id)
=dn1

f(d)=n/di=1g(id)μ(i)
f(d)=n/di=1(idn1)μ(i)

Ans=log2(n)i=1if(i)
=log(n)i=1in/ij=1(ijn1)μ(j)
设T = i *j
Ans=nT=1(Tn1)d|Tdμ(T/d)
=nT=1(Tn1)φ(T)
要使 (Tn1) 不等于0,缩小循环范围。
=log2(n)T=1(Tn1)φ(T)

对于每一个询问,可以在log时间内回答。

Code:

#include
#include
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;
ll a, b, phi[65];
int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}
ll sum(ll n) {
    ll ans = 0;
    fo(i, 1, log2(n)) ans += ((ll)pow(n, (long double)1 / i) - 1) * phi[i];
    return ans;
}
int main() {
    phi[1] = 1; fo(i, 1, 64) fo(j, i + 1, 64) if(gcd(i, j) == 1) phi[j] ++;
    for(scanf("%lld %lld", &a, &b); a != 0 || b != 0; scanf("%lld %lld", &a, &b))
        printf("%lld\n", sum(b) - sum(a - 1));
}

你可能感兴趣的:(莫比乌斯反演)