zoukankan      html  css  js  c++  java
  • [2019.1.10]BZOJ1853 [Scoi2010]幸运数字

    首先,我们可以预处理(r)以内的幸运数字。

    这样的数字不会很多,设(r)内所有幸运数字有(n)个,分别是(a_1,a_2,a_3,...,a_n)

    然后,我们知道(m)以内的(x)的倍数有(lfloorfrac{m}{x} floor)个。

    那么答案就是(sum_{i=1}^nlfloorfrac{r}{a_i} floor-sum_{i=1}^nlfloorfrac{l-1}{a_i} floor)?

    当然不是,因为会有重复。

    所以考虑容斥。

    我们设(f(m,x)=sum_{i_1=1}^nsum_{i_2=i_1+1}^nsum_{i_3=i_2+1}^n...sum_{i_x=i_{x-1}+1}^nlfloorfrac{m}{lcm(p_{i_1},p_{i_2},p_{i_3},...,p_{i_n})} floor),即任意(x)个幸运数字的最小公倍数 小于等于(m)的倍数数量和。

    那么答案就是(sum_{i=1}^n(-1)^{i+1}f(r,i)-sum_{i=1}^n(-1)^{i+1}f(l-1,i))

    可惜这样做时间复杂度很高,无法承受。

    考虑剪枝。

    (ans(x)=sum_{i=1}^n(-1)^{i+1}f(x,i)),那么问题答案就是(ans(r)-ans(l-1))

    看看如何计算(ans(m))

    首先,我们发现当任意数量的幸运数字的(lcm)大于(m)的时候,就不存在对答案的贡献了。

    所以我们可以减去(lcm)已经大于(m)的情况。

    这样就省掉了大量无意义运算。

    这样能不能通过此题呢?事实证明不能。

    还有以下优化:

    1.降序排列(p),使得(lcm)可以更快地大于(m)

    然后你吸个氧气可能就过了。

    如果你还是过不了,我们可以减少(p)的长度。

    2.发现对于任意(p_j|p_i),(p_i)的倍数都是(p_j)的倍数。

    所以删去(p_i)不会影响答案。

    然后应该是铁定过了。

    评测记录(吸了氧气)

    所有优化

    只有2

    只有1的莫名WA掉了,提交记录就不放了。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    const int p[15]={0,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1};
    long long l,r,n,ln[1050],sz,ued[1050],ans;
    queue<long long>q;
    long long gcd(long long x,long long y){
        return y?gcd(y,x%y):x;
    }
    long long lcm(long long x,long long y){
        return x?x*(y/gcd(x,y)):y;
    }
    bool P(long long x,long long y){
        return ((x<=1e9)||(y<=1e9));
    }
    bool cmp(long long x,long long y){
        return x>y;
    }
    void Getln(){
        long long x;
        q.push(6),q.push(8);
        while(!q.empty()){
            x=q.front(),q.pop();
            for(int i=1;i<=sz;++i)if(x%ln[i]==0)goto END;
            ln[++sz]=x;
            END:
            x*10+6<=r?(q.push(x*10+6),(x*10+8<=r?q.push(x*10+8),0:0)):0;
        }
    }
    void dfs(int x,int tt,long long lm){
        (x>sz&&lm)?ans+=p[tt]*(n/lm):0;
        if(x>sz||lm>n)return;
        dfs(x+1,tt,lm),P(lm,ln[x])?dfs(x+1,tt+1,lcm(lm,ln[x])),0:0;
    }
    long long Work(long long x){
        ans=0,n=x,dfs(1,0,0);
        return ans;
    }
    int main(){
        scanf("%lld%lld",&l,&r);
        Getln();
        sort(ln+1,ln+sz+1,cmp);
        printf("%lld",Work(r)-Work(l-1));
        return 0;
    }
    
  • 相关阅读:
    HDU 4278 Faulty Odometer 8进制转10进制
    hdu 4740 The Donkey of Gui Zhou bfs
    hdu 4739 Zhuge Liang's Mines 随机化
    hdu 4738 Caocao's Bridges tarjan
    Codeforces Gym 100187M M. Heaviside Function two pointer
    codeforces Gym 100187L L. Ministry of Truth 水题
    Codeforces Gym 100187K K. Perpetuum Mobile 构造
    codeforces Gym 100187J J. Deck Shuffling dfs
    codeforces Gym 100187H H. Mysterious Photos 水题
    windows服务名称不是单个单词的如何启动?
  • 原文地址:https://www.cnblogs.com/xryjr233/p/BZOJ1853.html
Copyright © 2011-2022 走看看