[JXOI2018]游戏

题目

人生第二道可怜题,依旧来自于\(JXOI\)

首先发现这个东西长得和分手是祝愿差不多,于是考虑一下贪心

显然贪心的策略应该是从小到大一个一个试,遇到一个不能表示成前面的数的倍数的数就把这个数选上

先用类似埃筛的东西求出这样的数的个数\(m\)

如果\(t(p)=i\),那么这\(m\)个都必须在\(i\)步之前完成,而且第\(i\)个正好要是这\(m\)中的一个

于是答案就是

\[\sum_{i=m}^ni\times m\times A(i-1,m-1)\times (n-m)!\]

就是强行枚举在第\(i\)步完成,之后让第\(i\)次访问一个没有被筛到的,剩下的\(m-1\)个我们让排列在前\(i-1\)个位置里,剩下\(n-m\)个没啥用的我们让它们排列一下

就没了

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<bitset>
#define maxn 10000005
#define re register
#define LL long long
const LL mod=1e9+7;
std::bitset<maxn> f;
int l,r,m;
LL fac[maxn],inv[maxn];
LL ans;
inline LL quick(LL a,LL b) {LL S=1;while(b) {if(b&1ll) S=S*a%mod;b>>=1ll;a=a*a%mod;}return S;}
inline LL A(int n,int m) {if(n<m) return 0;return fac[n]*inv[n-m]%mod;}
int main() {
    scanf("%d%d",&l,&r);
    for(re int i=l;i<=r;i++) {
        if(f[i]) continue;m++;
        for(re int j=i;j<=r;j+=i) f[j]=1; 
    }
    fac[0]=1;for(re int i=1;i<=r-l+1;i++) fac[i]=(fac[i-1]*i)%mod;
    inv[0]=1;inv[r-l+1]=quick(fac[r-l+1],mod-2);
    for(re int i=r-l;i>=0;--i) inv[i]=(inv[i+1]*(LL)(i+1))%mod;
    for(re int i=m;i<=r-l+1;i++) {
        ans=(ans+A(i-1,m-1)*(LL)i%mod)%mod;
    }
    printf("%lld\n",fac[r-l+1-m]*ans%mod*(LL)m%mod);
    return 0;
}
上一篇:各种技巧摘抄


下一篇:CF960G