来源:2009 Shanghai Invitation Contest Host by DHU
思路:sum[a, b] = sum[2, b] - sum[2,a-1].
枚举指数i,计算出在区间内可以表示成p^i的个数。值得注意的是若在区间[2, 64]内,i = 2时,a[2] = 7(2,3,4,5,6,7,8),其中4,8不应包含在内,因为4^2= 2^4,8^2=2^6,所以在最后计算i次方个数的时候需要把i次方的倍数个数剪掉。
#include<stdio.h>
#include<string.h>
#include<math.h>
#include <iostream>
using namespace std;
typedef __int64 lint;
lint ar[200],br[200], a[200];
const double eps = 1e-6;
lint n,m;
lint solve() {
lint p, i, j, tmp, cnt;
cnt = 0;
memset(ar,0,sizeof(ar));
memset(br,0,sizeof(br));
memset(a,0,sizeof(a));
tmp = m;
while (tmp) {
cnt++;
tmp >>= 1;
}
if (n == m) {
i = cnt;
for (; i>0; i--) {
if(i == 1)
return 1;
p = (lint)pow(n*1.0, 1.0/i+eps);
tmp = 1;
j = i;
while(j--) {
tmp *= p;
}
if (tmp == n)
return i;
}
}
else {
i = cnt;
for (; i > 0; --i) {
if (i == 1) {
ar[1] = m;
br[1] = n -1;
}
else {
p = (lint)pow(n*1.0, 1.0/i+eps);
while (1) {
j = i;
tmp = 1;
while(j--) {
tmp *= p;
}
if (tmp < n) {
br[i] = p;
break;
}
else {
p--;
}
}
p = (lint)pow(m*1.0, 1.0/i+eps);
j = i;
while (1) {
tmp = 1;
j = i;
while (j--) {
tmp *= p;
}
if (tmp <= m) {
ar[i] = p;
break;
}
else p--;
}
}
}
for (i = cnt; i > 0; --i) {
a[i] = ar[i] - br[i];
for (j = i + i; j <= cnt; j += i)
a[i] -= a[j];
}
lint sum = 0;
for (i = 1; i <= cnt; ++i)
sum += i*a[i];
return sum;
}
}
int main()
{
while (scanf("%I64d%I64d",&n,&m)!=EOF) {
if(n==0&&m==0)
break;
printf("%I64d\n", solve());
}
return 0;
}