[JXOI2018]游戏
Posted pigba
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[JXOI2018]游戏相关的知识,希望对你有一定的参考价值。
https://www.luogu.org/problemnew/show/P4562
一道不错的题
题意:给一个区间[l,r],当选择一个数i时,所有i的倍数都会被标记,然后对于一个[l,r]的排列,价值为到第几个数所有数都被标记,求所有排列价值之和
我们找出这样的数,只有它自己能标记自己。可以利用素数筛法去做,对于一个数有i>=l的因子去标记这个数,最后没有被标记的数则为这种特殊的数
发现当选完所有特殊的数时,这个序列就全选完了
设总共有x个这种数
然后枚举价值为i的序列,它左边放了x-1个特殊数,并在这个位置放了最后一个,这样就是组合数*阶乘
就是c(i-1,x-1)*(jc[x]*jc[n-x])
然后就可以了
本题重点是筛法筛出特殊数
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int N=1e7+5; const int P=1e9+7; int l,r,n; ll jc[N],inv[N]; int pri[N]; bool g[N],c[N]; ll qpow(ll x,ll y) { ll ret=1; while(y) { if(y&1) ret=ret*x%P; x=x*x%P; y>>=1; } return ret; } ll C(int n,int m) { return jc[n]*inv[m]%P*inv[n-m]%P; } int main() { scanf("%d%d",&l,&r); n=r-l+1; jc[0]=1; for(int i=1;i<=r;i++) jc[i]=jc[i-1]*i%P; inv[r]=qpow(jc[r],P-2); for(int i=r;i;i--) inv[i-1]=inv[i]*i%P; int tot=0,cnt=0; ll ans=0; if(l==1) { ll t=n; printf("%lld\n",jc[n-1]*((1+t)*t/2%P)%P); return 0; } else { for(int i=2;i<=r;i++) { if(!g[i]) pri[++tot]=i; for(int j=1;j<=tot && i*pri[j]<=r;j++) { g[i*pri[j]]=1; if(i>=l) c[i*pri[j]]=1; if(i%pri[j]==0) break; } } for(int i=l;i<=r;i++) cnt+=(!c[i]); } for(int i=n;i>=cnt;i--) ans+=C(i-1,cnt-1)*i%P,ans%=P; ans=ans*jc[cnt]%P*jc[n-cnt]%P; printf("%lld\n",ans); return 0; }
以上是关于[JXOI2018]游戏的主要内容,如果未能解决你的问题,请参考以下文章