题目描述
九条可怜是一个热爱游戏的女孩子,她经常在网上和一些网友们玩一款叫做《僵尸危机》游戏。
在这款游戏中,玩家们会需要在成为僵尸之前与黑恶势力斗智斗勇,逃离被病毒感染的小岛。但是黑恶势力不会让玩家轻易得逞,他会把一些玩家抓走改造成僵尸。变成僵尸的玩家会攻击其他的玩家,被攻击的玩家会被”感染”,成为病毒的潜在宿主。
具体来说,游戏开始时,所有的玩家会获得一个L∼R的编号(如果一共有R−L+1个玩家),不同的玩家的编号不同。
游戏分轮次进行,在每一轮中一次会发生这样的事情。
•如果所有当前所有的正常人都已经被感染,那么游戏结束。
•不然,黑恶势力会在当前的正常人(包括被感染的人)中等概率随机一个改造成僵尸。
•被改造成僵尸的玩家会攻击所有编号是他的倍数的玩家,使得他们被感染。
九条可怜现在想知道,这个游戏期望会进行多少轮?这个答案可能是一个实数,她想让你给出期望轮数乘上(R−L+1)!以后的结果,这个结果可能很大,请对109+7取模后输出。
输入
第一行输入两个整数 L, R 表示编号范围。
输出
一个整数,表示期望进行的轮数。
样例输入
2 4
样例输出
16
提示
• 2 3 4, 轮数是 2。
• 3 2 4, 轮数是 2。
• 4 2 3, 轮数是 3。
• 4 3 2, 轮数是 3。
• 2 4 3, 轮数是 3。
• 3 4 2, 轮数是 3。
每种情况的概率都是 1/6,于是期望轮数就是 (2 + 2 + 3 + 3 + 3 + 3)/6 =8/3。
乘上 3! = 6 以后就是 16 。
对于 20% 的数据,R − L + 1 ≤ 8。
对于另 10% 的数据,L = 1。
对于另 10% 的数据,L = 2。
对于另 30% 的数据,L ≤ 200。
对于 100% 的数据,1 ≤ L ≤ R ≤ 107 。
来源/分类
求的是 总和, 不是期望
线性筛 非倍数个数 cot, 组合公式求 结果 n = r-l+1 区间长度
然后 按照公式 逆元 + 阶乘 瞎搞一波,
[代码]
#include <iostream>
#include <bits/stdc++.h>
#define rep(i,a,n) for(ll i = a;i<n;i++)
#define per(i,a,n) for(ll i = n-1;i>=a;i++)
typedef long long ll;
typedef unsigned long long llu;
const int mod = 1e9+7;
const int MAXN= 2e7+150;
using namespace std;
inline ll qpow(ll a,ll n)
{
ll ans = 1;
for(;n;n>>=1)
{
if(n&1)
{
ans = (ans*a) %mod;
}
a = (a*a) %mod;
}
return ans;
}
ll n,cot;
int vis[MAXN];
ll inv[MAXN];
ll fac[MAXN];
ll l, r;
void init()
{
cot = 0;
rep(i,l,r+1)
{
if(vis[i])
continue;
cot++;
for(ll j=2;j*i<=r;j++)
vis[i*j]=1;
}
}
void work()
{
fac[0] = 1;
rep(i,1,n+1)
fac[i] = (fac[i-1]*i )%mod;
inv[n-cot] = qpow(fac[n-cot],mod-2);
for(ll i = n-1-cot; i>=0 ;i--)
inv[i] = ( inv[i+1]*(i+1) ) %mod;
ll ans = 0;
rep(i,cot,n+1)
ans = (ans + ( ((cot*fac[i])%mod *fac[n-cot])%mod*inv[i-cot])%mod)%mod;
cout<<ans<<endl;
}
int main()
{
scanf("%lld %lld",&l,&r);
n = r-l+1;
init();
work();
return 0;
}