HDU-3208-Integer’s Power
题意就是定义
power(x)
p
o
w
e
r
(
x
)
为
x
x
能被表示为中最大的
k
k
,例如,给出
l,r
l
,
r
计算
Σri=lpower(i)
Σ
r
i
=
l
p
o
w
e
r
(
i
)
很明显可以将题意转化为
Σri=1power(i)−Σl−1i=1power(i)
Σ
r
i
=
1
p
o
w
e
r
(
i
)
−
Σ
l
−
1
i
=
1
p
o
w
e
r
(
i
)
由于这题要求可以被表示的最大次幂,我们就不能像上一题一样容斥,因为某些数表示为 m4 m 4 比表示为 (m2)2 ( m 2 ) 2 更优,所以我们要先算出所有数作为次幂可能的出现次数,由于 260>1018 2 6 0 > 10 1 8 所以我们只需要算到60即可,在预处理出这个数组之后,我们就可以进行容斥,这道题要怎么容斥呢,我们想一下比如我们计算6作为次幂出现的次数为 dp[6] d p [ 6 ] ,那么这之中肯定已经包含了 dp[2] d p [ 2 ] 和 dp[3] d p [ 3 ] 中的一部分,相对于2,3,我们肯定选择6,因为他更大,所以我们要让 dp[2]−=dp[6],dp[3]−=dp[6] d p [ 2 ] − = d p [ 6 ] , d p [ 3 ] − = d p [ 6 ] ,很明显我们要对某个数的所有因子项减去当前数的出现次数,怎么保证每个数组做贡献的时候是最终状态呢,我们只要逆序去dp就可以了,这样就保证了每个数组去更新其他数组的时候也自己已经是最终状态。另外这题利用 pow(x,1/y) p o w ( x , 1 / y ) 去计算 x−−√y x y 具有精度问题,所以要在求出之后左右判一下精度问题。
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll dp[63];
ll pow_(ll x,int n)
{
ll ans=1;
while(n)
{
if(n&1)
{
double tmp=1.0*INF/ans;
if(x>tmp) return -1;
ans*=x;
}
n>>=1;
if(x>((ll)1<<31)&&n) return -1;
x=x*x;
}
return ans;
}
ll cal(ll x,ll n)//返回精确的\sqrt[y]{x}
{
ll a=(ll)pow(x,1.0/n);
ll qt=pow_(a,n);
ll ql=pow_(a-1,n);
ll qr=pow_(a+1,n);
if(qr!=-1&&qr<=x) return a+1;
else if(qt!=-1&&qt<=x) return a;
else if(ql!=-1&&ql<=x) return a-1;
}
ll solve(ll n)
{
if(n==1) return 1;
int i,j;
memset(dp,0,sizeof(dp));
dp[1]=n;
for(i=2;i<63;i++)
{
dp[i]=cal(n,i)-1;
if(dp[i]==0) break;
}
int k=i;
for(i=k-1;i>0;i--)//逆序DP
{
for(j=1;j<i;j++)
{
if(i%j==0) dp[j]-=dp[i];
}
}
ll ans=0;
for(int i=1;i<k;i++) ans+=1LL*i*dp[i];
return ans;
}
int main()
{
ll l,r;
while(scanf("%lld%lld",&l,&r)!=EOF)
{
if(l==0&&r==0) break;
printf("%lld\n",solve(r)-solve(l-1));
}
return 0;
}