[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;
}