[JXOI2018]游戏

题意

实在描述不来\(orz\)
[JXOI2018]游戏

想法

我们考虑用筛法,把\([l,r]\)之间的质数全部标记起来,那么就有\(sum\)个质数,这些质数是都要被巡一遍的
我们考虑\(f(i)\)为最后一个质数被检查在\(i\)时刻的方案数
那么有\(f(i) = (i - 1)! * A(n - sum,n - i) * sum\)
作为最后一个质数有\(sum\)种,前\(i - 1\)个数排列,然后后\(n - i\)个数是随意的

代码

#include<iostream>
#include<cstdio>
#define ll long long 

ll l,r;

ll mod = 1e9 + 7,cnt;

bool vis[10000005];

void sieve(){
	for(int i = l;i <= r;++i){
		if(!vis[i]){
			++cnt;
			for(int j = 1;j * i <= r;++j)
			vis[j * i] = 1;
		}
	}
}

ll ans,n,fac[10000005],inv[10000005];

ll qpow(ll a,ll b){
	ll ans = 1;
	while(b){
		if(b & 1) ans = 1ll * ans * a % mod;
		a = 1ll * a * a % mod;
		b >>= 1;
	}
	return ans;
}

ll A(ll n,ll m){return 1ll * fac[n] * inv[n - m] % mod;}

ll f(ll now){return 1ll * fac[now - 1] * cnt %mod * A(n - cnt,n - now) % mod;}

int main(){
	scanf("%lld%lld",&l,&r);
	sieve();
	n = r - l + 1;
	fac[0] = 1;
	//std::cout<<cnt<<std::endl;
	for(int i = 1;i <= r;++i)
	fac[i] = 1ll * fac[i - 1] * i % mod;
	//puts("");
	inv[r] = qpow(fac[r],mod - 2);
	for(int i = r - 1;i >= 0;--i)
	inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
	for(int i = cnt;i <= n;++i)
	ans = ans + i * f(i) % mod;
	std::cout<<ans % mod;
}

(不要忘记最后答案取膜 求\(inv\)要求到\(0\))

posted @ 2021-01-13 21:50  fhq_treap  阅读(80)  评论(0编辑  收藏  举报