解题:JXOI 2018 游戏

题面

From ZRQ,很好的计数题

我们可以发现这$len=r-l+1$个数中有一些是必须被查到的,即它们不是一些数的倍数,它们的数目$imp$可以通过一次埃氏筛求出。

在一个排列中可怜查到某个位置时就不用检查了,那这个位置上一定是这个排列中第$imp$和必须被查的数,我们不妨从$imp$到$len$枚举这个这个位置$i$。那么这个位置上的数有$imp$种可能,答案乘上$imp$;前面这$i$个数中要塞上$i-imp$个不必须的数,答案乘上$C_{len-imp}^{i-imp}$;最后是这个点前后各有$(i-1)!$和$(len-i)$种排列,答案也要乘上这两个。最后答案即

$sumlimits_{i=imp}^{len}imp*C_{len-imp}^{i-imp}*(i-1)!*(len-i)!$

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=1e7+70;
 6 const long long mod=1e9+7;
 7 long long facs[N],inv[N];
 8 long long l,r,len,imp,ans;
 9 bool mark[N];
10 long long qpow(long long x,long long k)
11 {
12     if(k==1) return x;
13     long long tmp=qpow(x,k/2);
14     return k%2?tmp*tmp%mod*x%mod:tmp*tmp%mod;
15 }
16 void prework()
17 {
18     len=r-l+1,facs[0]=inv[0]=1;
19     for(int i=1;i<=len;i++)
20         facs[i]=facs[i-1]*i%mod;
21     inv[len]=qpow(facs[len],mod-2);
22     for(int i=len-1;i;i--)
23         inv[i]=inv[i+1]*(i+1)%mod;
24     for(long long i=l;i<=r;i++)
25         if(!mark[i])
26         {
27             imp++;
28             for(long long j=2*i;j<=r;j+=i)
29                 mark[j]=true;
30         }
31 }
32 long long C(long long n,long long m)
33 {
34     return facs[n]*inv[m]%mod*inv[n-m]%mod;
35 }
36 int main ()
37 {
38     scanf("%lld%lld",&l,&r),prework();
39     for(int i=imp;i<=len;i++)
40         ans+=imp*C(len-imp,i-imp)%mod*facs[i-1]%mod*facs[len-i]%mod*i%mod,ans%=mod;
41     printf("%lld",ans);
42     return 0;
43 }
View Code
原文地址:https://www.cnblogs.com/ydnhaha/p/9808748.html