/** 题目:H - Power of Integer 链接:https://vjudge.net/contest/152887#problem/H 题意:给出区间[a, b],问你区间[a, b]所有数的幂的和是多少,定义一个 数的幂是这样的:对于一个数y,存在一个最小的数x,有一个最大的k,使得x^k=y, 那k就是y的幂 思路:看到这种题目容易想到[2,b]-[2,a-1]的做法; 先对[2,b]考虑,因为[2,a-1]同它做法是一样的。一开始我想的是先求x^2<=b 求出最大的满足条件的x, 然后可以计算有多少个幂为2的数在该范围[2,x]内的数的2次方都在[2,b]内。然后再计算x^3<=b的最大的x;然后x^4,x^5,,,,到找不到为止。 但是这样做无法处理重复的情况。 我当时想了很久还是想不到,实在想不到。问了志轩的想法。 他说从高位到低位处理。 假设我求x^12<=b;那么得出一个区间[2,x]范围内的数。对其中某一个数xx^12<=b而这个xx^12是可以分解为(xx^6)^2,(xx^4)^3,(xx^3)^4,(xx^2)^6,(xx^12)^1; 这些可以划分的次方是原来数的约数,不包括本身12;这样就可以提前减去他们产生的贡献。随着幂减少,之后加到他们也不会有影响,因为已经减过了。 代码没有ac,精度问题。 最下面那份代码ac了。 另外做法:利用计算器预处理所有x^2<=10^18,x^3<=10^18,x^4<=10^18....的x值。然后计算的时候就可以控制好,防止溢出了。 */ #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const double eps = 1e-6; const int maxn = 1e9+100; int sum[64]; ll a, b; //预处理每个数的约数和(不包括自身) void getSum() { sum[1] = 0; for(int i = 2; i <= 63; i++){ for(int j = 1; j*2 <= i; j++){ if(i%j==0) sum[i]+=j; } } //test //printf("%d %d ",sum[8],sum[9]); } //判断是否满足x^y<=b bool judge(ll x,int y,ll b) { ll res = 1; for(int i = 1; i <= y; i++){ if(log(res)+log(x)-log(b)>=eps) return false; res *= x; } //return true; return res<=b; } //计算[2,x]范围内的power sum。 ll solve(ll y) { if(y<2) return 0; //求x^i<=y的x值。 ll ans = 0; for(int i = 63; i >= 1; i--){ ll mas = 1; ll lo = 1, hi = b, m; while(lo<=hi){ m = (lo+hi)/2; if(judge(m,i,y)){//满足条件 lo = m+1; mas = max(mas,m); }else { hi = m-1; } } //if(mas==1) continue; //cout<<"mas = "<<mas<<endl; //cout<<"i = "<<i<<endl; ans += 1LL*(i-sum[i])*(mas-1); } return ans; } int main() { getSum(); while(scanf("%lld%lld",&a,&b)==2&&a){ // ll p = 1; // a = b = p<<59;/// // b+=2; //cout<<"a = "<<a<<endl; //cout<<"solve(b) = "<<solve(b)<<endl; //cout<<"solve(a-1) = "<<solve(a-1)<<endl; printf("%lld ",solve(b)-solve(a-1)); } return 0; } ///from zzx /* from zzx 思路:由于要找的幂尽量大,所以我们要从高到低来枚举计算幂的贡献 对于幂k 二分一下范围[x,y] 满足a <= x ^ k <= y ^ k <= b 现在就是要去重了 举个例子 2^4 等于16 4^2也等于16 所以算完k为4的贡献后(假设为d),要除掉对k的所有约数的影响(显然影响也为d) ps: 被 long long 相乘时判溢出 坑了几波,还是取对数靠谱一些 */ /* #include<bits/stdc++.h> #define LL long long using namespace std; const double eps = 1e-6; LL a, b,cnt[64]; bool check1(LL x,int y) { LL res = 1; for(int i = 1; i <= y; i++) { if(log(res) + log(x) - log(a) >= eps) return true; res *= x; } return res >= a; } LL FindL(int y) { LL l = 1,r = b,ans = b; while(l <= r) { LL mid = (l + r) / 2; if(check1(mid,y)) ans = min(ans,mid),r = mid - 1; else l = mid + 1; } return ans; } bool check2(LL x,int y) { LL res = 1; for(int i = 1; i <= y; i++) { if(log(res) +log(x) - log(b) > eps) return false; res *= x; } return res <= b; } LL FindR(int y) { LL l = 1,r = b,ans = 1; while(l <= r) { LL mid = (l + r) / 2; if(check2(mid,y)) ans = max(ans,mid),l = mid + 1; else r = mid - 1; } return ans; } int main() { while(scanf("%lld%lld",&a,&b)&&(a+b)) { memset(cnt,0,sizeof(cnt)); LL ans = 0; for(int i = 63; i >= 1; i--) { LL x = FindL(i), y = FindR(i); LL d = max(y-x+1,0LL); if(d) { d -= cnt[i]; ans += i * d; if(d) { for(int k = 1; k * k <= i; k++) { if(i % k == 0){ cnt[k] += d; if(i/k!=k) cnt[i/k]+=d; } } } } } printf("%lld ",ans); } return 0; } */