[2019.1.10]BZOJ1853 [Scoi2010]幸运数字

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

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

然后,我们知道\(m\)以内的\(x\)的倍数有\(\lfloor\frac{m}{x}\rfloor\)个。

那么答案就是\(\sum_{i=1}^n\lfloor\frac{r}{a_i}\rfloor-\sum_{i=1}^n\lfloor\frac{l-1}{a_i}\rfloor\)?

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

所以考虑容斥。

我们设\(f(m,x)=\sum_{i_1=1}^n\sum_{i_2=i_1+1}^n\sum_{i_3=i_2+1}^n...\sum_{i_x=i_{x-1}+1}^n\lfloor\frac{m}{lcm(p_{i_1},p_{i_2},p_{i_3},...,p_{i_n})}\rfloor\),即任意\(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;
}
posted @ 2019-03-17 18:02  xryjr233  阅读(142)  评论(0编辑  收藏  举报