[JXOI2018]游戏
$ solution: $
这一道题的原版题面实在太负能量了,所以用了修改版题面。
这道题只要仔细读题,我们就可以将题目的一些基本性质分析出来:首先我们定义:对于某一类都可以被x整除的数(要在 $ [l,r] $ 之内),若x也在我们的 $ [l,r] $ 之内且x不能被 $ [l,r] $ 内任意其它数整除,我们称这类数为关联数且x为特殊数,(显然:当九条可怜查了x这间办公室后,所有以x为特殊数的关联数都不需要再检查了!)(而且:这一类以x为特殊数的关联数,只有且只要当x被检查后,这一类数都不需要检查了!)
然后我们可以将 $ [l,r] $ 内所有的数,都分为以不同数为特殊数的关联数。然后我们发现只有且只要当所有的特殊数都被检查后,整个 $ [l,r] $ 就都不需要检查了(这个可以根据上面括号里的第二条性质推出来)。所以我们用线性筛把这一类特殊数筛出来(我们不难发现对于一个数x,如果它除以它的最小因子(得到比它小的最大的约数),如果它不在 $ [l,r] $ 内,则说明它是一个特殊数)。然后我们可以枚举最后一个特殊数在操作序列中出现的位置(假设现在枚举到i),于是这个序列的后面一部分(即n-i个数)就无关紧要了,这相当于我们从tot(假设 $ [l,r] $ 中不是特殊数的有tot个)个非特殊数中取出n-i个数随便排列,然后i之前特殊数和非特殊数也可以随便排列。
于是我们得出答案就是:
$ ans=sum_{i=tot}^n i imes tot imes C binom{n-i}{n-tot} imes (n-i)! imes (i-1)! $
按顺序:(枚举最后一个特殊数的位置)(最后一个特殊数数在i结束,会有i的贡献)(这个位置可以是tot里的任意一个特殊数)(从剩下的非组合数n-tot个中取出n-i个放在i后面)(后面的n-i个非特殊数数可以随便排列)(前面的i-1个数也可以随便排列)
于是我们可以暴力求阶乘,阶乘逆元,还有线性筛即可。
$ code: $
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int
using namespace std;
const int mod=1e9+7;
int l,r,n,tot,ans;
int ni[10000005];
int jc[10000005];
int pr[10000005];
int use[10000005];
inline int qr(){
char ch;
while((ch=getchar())<'0'||ch>'9');
int res=ch^48;
while((ch=getchar())>='0'&&ch<='9')
res=res*10+(ch^48);
return res;
}
inline int ksm(ll x,int y,int p){
ll res=1;
while(y){
if(y&1)(res*=x)%=p;
(x*=x)%=p; y>>=1;
}return res;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
l=qr(); r=qr(); n=r-l+1; jc[0]=1;
for(rg i=1;i<=r;++i)
jc[i]=(ll)jc[i-1]*i%mod;
ni[r]=ksm(jc[r],mod-2,mod);
for(rg i=r;i;--i)
ni[i-1]=(ll)ni[i]*i%mod;
if(l==1){printf("%lld
",(ll)jc[r]*(n+1)%mod*ksm(2,mod-2,mod)%mod);return 0;}
for(rg i=2;i<=r;++i){
if(!use[i])use[i]=i,pr[++tot]=i;
for(rg j=1;j<=tot;++j){
if(pr[j]*i>r)break;
use[pr[j]*i]=pr[j];
if(!(i%pr[j]))break;
}
} tot=0;
for(rg i=l;i<=r;++i)if(i/use[i]<l)++tot;
for(rg i=tot;i<=n;++i){
(ans+=(ll)tot*jc[n-tot]%mod*jc[i]%mod*ni[i-tot]%mod)%=mod;
}printf("%d
",ans);
return 0;
}