zoukankan      html  css  js  c++  java
  • SCOI2010 幸运数字

    题目链接:戳我

    lcm相关 容斥+搜索剪枝

    选一个数的近似幸运号码,但是这样子可能有两个或多个的数的倍数相同——所以考虑容斥——我们把两个的减去。但是这样一来是三个数的lcm的数的就没有计算到,我们再加上它。。。。。。

    trick1——把合法的数先预处理出来,方便之后操作。

    trick2——我们从小到大判断,如果一个数已经是前面一个数的倍数了,就无需记录它了,反正它的近似幸运数字都被包含于那个数字的近似幸运数字。

    trick3——如果当前的lcm到达了上届(也就是题目中的B)我们就无需再搜索了(显然吧)

    trick4——从大到小暴搜,可以使得lcm更快地达到上届。

    最后,我们不需要先计算出[1,r]和[1,l-1]的,然后再相减计算答案。对于一个数x,区间[A,B]内它的倍数其实就是(lfloorfrac{B}{x} floor+lceilfrac{A}{x} ceil+1)

    qwqwqwq代码如下:

     #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define MAXN 100010
    using namespace std;
    int tot,n;
    int done[MAXN];
    long long A,B,ans;
    long long num[MAXN],pre[MAXN];
     
    inline void init(int cnt,int limit,long long val,long long base)
    {
        //printf("cnt=%d limit=%d val=%lld base=%lld
    ",cnt,limit,val,base);
        if(cnt>limit) {pre[++tot]=val;return;}
        init(cnt+1,limit,val+6*base,base*10);
        init(cnt+1,limit,val+8*base,base*10);
    }
    
    inline bool cmp(long long x,long long y){return x>y;}
    
    inline long long gcd(long long x,long long y){return y==0?x:gcd(y,x%y);}
    
    inline long long calc(long long x)
    {
        long long cur_ans=0;
        cur_ans=B/x-A/x-(A%x!=0)+1;
        return cur_ans;
    }
    
    void search(int dep,int cnt,long long val) 
    {
        if (val>B) return;
        if (dep>n) 
    	{
            if (cnt==0) return;
            ans+=calc(val)*((cnt&1)?1:-1);
            return;
        }
        search(dep+1,cnt,val);
        long long tmp=val/gcd(val,num[dep]);
        if(1.0*tmp*num[dep]<=B)
            search(dep+1,cnt+1,tmp*num[dep]);
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        freopen("ce.out","w",stdout);
        #endif
        cin>>A>>B;
        for(int i=1;i<=10;i++) init(1,i,0,1);
        for(int i=1;i<=tot;i++)
        {
            if(!done[i]) num[++n]=pre[i];
            for(int j=i+1;j<=tot;j++)
                if(pre[j]%pre[i]==0) done[j]=1;
        }
        sort(&num[1],&num[n+1],cmp);
        search(1,0,1);
        cout<<ans<<endl;
        return 0;
    }
    
  • 相关阅读:
    BZOJ2219数论之神——BSGS+中国剩余定理+原根与指标+欧拉定理+exgcd
    Luogu 3690 Link Cut Tree
    CF1009F Dominant Indices
    CF600E Lomsat gelral
    bzoj 4303 数列
    CF1114F Please, another Queries on Array?
    CF1114B Yet Another Array Partitioning Task
    bzoj 1858 序列操作
    bzoj 4852 炸弹攻击
    bzoj 3564 信号增幅仪
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10432725.html
Copyright © 2011-2022 走看看