正题
题目链接:https://www.luogu.org/problemnew/show/P4562
题目大意
l∼rl\sim rl∼r的变化,每次访问第iii个那么iii的倍数就不用访问了。对于一个顺序sss,定义t(s)t(s)t(s)表示按这个顺序访问玩前t(s)t(s)t(s)个就都不用访问了。求所有顺序的t(s)t(s)t(s)之和。
解题思路
若l==1l==1l==1时那么只要访问111就好了,所以答案是r!∗(r+1)2\frac{r!*(r+1)}{2}2r!∗(r+1)
若l!=1l!=1l!=1时我们用质数筛的方法计算有多少个是需要访问的,定义个数为mmm,然后我们用iii枚举t(s)t(s)t(s),首先这样的序列有m∗Cn−in−sum∗(i−1)!∗(n−i)!m*C^{n-sum}_{n-i}*(i-1)!*(n-i)!m∗Cn−in−sum∗(i−1)!∗(n−i)!
Cn−in−sumC^{n-sum}_{n-i}Cn−in−sum表示后面不用选的方案数,然后(n−i)!(n-i)!(n−i)!将其排列,(i−1)!(i-1)!(i−1)!表示前面的排列顺序
然后乘上一个iii表示t(s)t(s)t(s)
codecodecode
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e7+10,XJQ=1e9+7;
ll l,r,fac[N],inv[N],ans,sum,n;
bool v[N];
ll power(ll x,ll b){ll ans=1;while(b){if(b&1) ans=(ans*x)%XJQ;x=(x*x)%XJQ;b>>=1;}return ans;
}
int main()
{scanf("%lld%lld",&l,&r);n=r-l+1;fac[0]=1;for(ll i=1;i<=r;i++)fac[i]=fac[i-1]*i%XJQ;inv[r]=power(fac[r],XJQ-2);for(ll i=r;i;i--)inv[i-1]=inv[i]*i%XJQ;if(l==1){printf("%lld",fac[r]*(r+1)%XJQ*power(2,XJQ-2)%XJQ);return 0;}for(ll i=l;i<=r;i++){if(v[i]) continue;sum++;for(ll j=i*2;j<=r;j+=i)v[j]=1;}for(ll i=sum;i<=n;i++)(ans+=sum*fac[n-sum]%XJQ*inv[i-sum]%XJQ*fac[i]%XJQ)%=XJQ;printf("%lld",ans);
}