zoukankan      html  css  js  c++  java
  • 容斥原理——hdu3208

    和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;
    }
  • 相关阅读:
    计时器C#
    MySQL Database Command Line Client
    C#小爬虫,通过URL进行模拟发送接收数据
    C#导入导出Excele数据
    正则表达式动态分隔符
    C#中的枚举
    C#中的ToString格式大全
    C# 序列化与反序列化
    C# 对xml进行操作
    时间标签DateTime
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10859871.html
Copyright © 2011-2022 走看看