容斥原理——hdu3208

本文探讨了在处理大规模数值运算时如何解决精度问题,特别是针对pow函数的精度不足,提出了手动扩大精度的方法,并通过容斥原理求解特定数学问题。代码示例使用C++实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

和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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值