洛谷P4562 [JXOI2018]游戏

题目

https://www.luogu.com.cn/problem/P4562
沉迷水题无法自拔(感觉校赛要大寄特寄qwq)

思路

可以fa现可怜的检查和员工的通风报信类似一个筛法的过程,当区间中所有的数都被筛到至少一遍时,这个过程就结束了。

然后我们考虑什么情况下区间会被筛完。简单分析一下可知,对于\(a\in [l,r]\),如果\(\exists b\neq a,b\in [l,r]\) 使得 \(b|a\) ,那么\(a\)对筛是没有贡献的,相当于没有筛。

因为\(a\)能筛到的\(b\)都能筛到,而且\(b\)必须筛一遍以保证它本身被筛到。

所以我们可以定义关键数:区间内不存在它的因数。于是\(t(p)=n\)意味着在排列的前n个数中,所有的关键数都出现了(满足n最小)。

所以在找出所有关键数之后,我们可以枚举最后一个关键数出现的位置,写出一个式子(假设一共有\(s\)个关键数,区间长度为\(n=r-l+1\)):

\[s!*(n-s)!\sum_{k=1}^{n} k*\tbinom{k-1}{s-1} \]

前面是个常量,我们关注和式。

这个东西用生成函数求导的方法当然很套路,但是如果没有学过生成函数也没关系,我们有\(k\tbinom{k-1}{s-1}=s\tbinom{k}{s}\),把\(s\)提出去就是一个平行求和。

不管用什么方式,我们都可以得到\(s\tbinom{n+1}{s+1}\) 这个式子。

所以最终答案就是

\[s!*(n-s)!*s*\tbinom{n+1}{s+1} \]

尽管算法时间复杂度的瓶颈并不在这里,但是有了封闭形式的结果总是令人愉快的 ⊂(‘ω’⊂ )))

然后我们考虑如何计算这个\(s\)。之前说过所谓的关键数满足:区间内不存在它的因数,这个性质与质数有几分相似,这启发我们,是不是只要对筛法进行一些魔改就能成功呢?

然后我们试着改一下欧拉筛。

然后我们就AC了(雾)。

代码

点击查看代码
#include<cstdio>
#include<cstdlib>
#define maxn (int)(1e7+10)
#define mod ((int)(1e9+7))
#define ll long long
using namespace std;
int l,r,book[maxn],p[maxn],cnt=0;
int f[maxn];
ll fac[maxn];
ll qpow(ll x,int p){
    ll ans=1,base=x;
    for(;p;p>>=1){
        if(p&1) ans=ans*base%mod;
        base=base*base%mod;
    }
    return ans;
}
ll inv(ll x){
    return qpow(x,mod-2);
}
ll C(int n,int m){
    return fac[n]*inv(fac[m])%mod*inv(fac[n-m])%mod;
}
int main(){
    int i,j,n,m,sum=0;
    ll ans=0;
    scanf("%d%d",&l,&r);
    if(l==1){
        for(i=1;i<=r;++i) ans=(ans+i)%mod;
        for(i=1;i<r;++i) ans=ans*i%mod;
        printf("%lld",ans);
        return 0;
    }
    for(i=2;i<=r;++i){
        if(!book[i]) p[++cnt]=i;
        for(j=1;j<=cnt&&p[j]<=r/i;++j){
            book[i*p[j]]=1;
            if(!(i%p[j])) break;
        }
    }
    for(i=l;i<=r;++i){
        if(!f[i]) sum++;
        for(j=1;j<=cnt&&p[j]<=r/i;++j){
            f[i*p[j]]=1;
            if(!(i%p[j])) break;
        }
    }
    n=r-l+1;
    fac[0]=1;
    for(i=1;i<=n+1;++i) fac[i]=fac[i-1]*i%mod;
    ans=sum*C(n+1,sum+1)%mod;
    // for(i=sum;i<=n;++i){
    //     ans+=i*C(i-1,sum-1);
    // }
    ans=ans*fac[n-sum]%mod*fac[sum]%mod;
    printf("%lld",ans);
    // system("pause");
    return 0;
}
posted @ 2022-05-09 22:17  文艺平衡树  阅读(50)  评论(0编辑  收藏  举报