hdu 3208 容斥原理

LMY and YY are number theory lovers. They like to find and solve some interesting number theory problems together. One day, they become interested in some special numbers, which can be expressed as powers of smaller numbers.

For example, 9=3^2, 64=2^6, 1000=10^3 …

For a given positive integer y, if we can find a largest integer k and a smallest positive integer x, such that x^k=y, then the power of y is regarded as k.
It is very easy to find the power of an integer. For example:

The power of 9 is 2.
The power of 64 is 6.
The power of 1000 is 3.
The power of 99 is 1.
The power of 1 does not exist.

But YY wants to calculate the sum of the power of the integers from a to b. It seems not easy. Can you help him?

Input The input consists of multiple test cases.
For each test case, there is one line containing two integers a and b. (2<=a<=b<=10^18)

End of input is indicated by a line containing two zeros. Output For each test case, output the sum of the power of the integers from a to b. Sample Input
2 10
248832 248832
0 0
Sample Output
13
5


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const double eps = 1e-8;
const ll inf = (ll)(1e18) + 500;
const ll INF = (ll)1 << 31;
ll num[110];


ll quick_pow(ll a, ll b) //快速幂求a ^ b,考虑溢出
{
    ll res = 1, tmp = a;
    while(b) 
	{
        if(b & 1) 
		{
			double t = 1.0*inf / res; 
            if(tmp > t) 
				return -1;
            res *= tmp;
        }
        b >>= 1;
        if(tmp > INF && b > 0) 
			return -1;
        tmp *= tmp;
    }
    return res;
}

ll find(ll a, ll b)  //比较精确地求a ^ (1 / b)(向下取整) 
{
    ll x = (ll)(pow((double)(a), 1.0 / b) + eps); 
    ll y = quick_pow(x, b);
    if(y == a) 
		return x;
    if(y == -1 || y > a) 
		return x - 1;
    y = quick_pow(x + 1, b);
    if(y != -1 && y <= a) 
		return x + 1;
    else 
		return x;
}

ll solve(ll n) //求[1, n]的指数和
{
    memset(num, 0, sizeof(num));
    int total;
    num[1] = n;
    for(ll i = 2; i < 63; ++i) // 枚举指数的范围 
	{
        num[i] = find(n, i) - 1; //不考虑1
        if(num[i] == 0) 
		{
            total = i;
            break;
        }
    }
    for(int i = total - 1; i >= 1; --i) 
        for(int j = 1; j < i; ++j) 
		{
            if(i % j == 0) 
				num[j] -= num[i]; // 容斥原理减去重复的  例如 2^6 = 4^3 = 8^2
        }
    ll ans = num[1];
    for(int i = 2; i < total; ++i) 
        ans += i * num[i]; 
    return ans;
}

int main()
{
    ll n, m;
    while(~scanf("%lld%lld", &n, &m)) 
	{    
		if(n==0 && m==0)
			break;
        printf("%lld\n", solve(m) - solve(n - 1));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38295645/article/details/80368136