和hdu2204有点像
这题要特别注意精度问题,如pow的精度需要自己搞一下,然后最大的longlong可以设为1<<31
/* 只要求[1,n]范围内的sum即可 那么先枚举幂次k[1,63] 然后求 x^k<=n,x的最大取值sum[i](这里要扩大一下pow的精度) 然后进行容斥,j%i==0,si-=sj */ #include<bits/stdc++.h> using namespace std; #define ll long long #define INF (ll)1<<31 #define esp 1e-18 ll sum[100]; const double inf=1e18+500; /* ll Pow(ll a,ll b){//防越界的快速幂 ll res=1; while(b){ if(b%2){ double judge=1.0*inf/res; if(a>judge)return -1;//必须先判断res*a是否会越界 res=res*a; } b>>=1; if(a>INF && b>0)return -1;//判断a是否越界了 a=a*a; } return res; } ll calc(ll k,ll n){ ll x=(ll)pow(n,1.0/k),t,p; p=Pow(x,k); if(p==n)return x;//刚好相等 if(p>n || p==-1) x--;//越界了 else {//判断x是否能再+1 t=Pow(x+1,k); if(t!=-1 && t<=n)x++; } return x; } */ ll multi(ll a,ll b)//快速乘 { ll ans=1; while(b){ if(b&1){ double judge=1.0*inf/ans; if(a>judge) return -1; ans*=a; } b>>=1; if(a>INF&&b>0) return -1; a=a*a; } return ans; } ll Find(ll x,ll k)//手动扩大pow精度 { ll r=(ll)pow(x,1.0/k); ll t,p; p=multi(r,k); if(p==x) return r; if(p>x||p==-1) r--; else { t=multi(r+1,k); if(t!=-1&&t<=x) r++; } return r; } ll solve(ll n){ if(n==0)return 0; ll res=0,Max=0; memset(sum,0,sizeof sum); sum[1]=n; for(ll k=2;k<=63;k++){ sum[k]=Find(n,k);//求扩精度后的最大的x if(sum[k])sum[k]--;//1特判 if(sum[k]==0){Max=k;break;} } //容斥 for(int j=Max;j>=2;j--) for(int i=1;i<j;i++) if(j%i==0)sum[i]-=sum[j]; for(int i=1;i<=Max;i++)res+=sum[i]*i; return res; } int main(){ ll L,R; while(cin>>L>>R && R) cout<<solve(R)-solve(L-1)<<endl; }
原文:https://www.cnblogs.com/zsben991126/p/10859871.html