upc 6887: 游戏(组合数学)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/winter2121/article/details/81533003

6887: 游戏

时间限制: 1 Sec  内存限制: 512 MB
提交: 260  解决: 83
[提交] [状态] [讨论版] [命题人:admin]

题目描述

九条可怜是一个热爱游戏的女孩子,她经常在网上和一些网友们玩一款叫做《僵尸危机》游戏。
在这款游戏中,玩家们会需要在成为僵尸之前与黑恶势力斗智斗勇,逃离被病毒感染的小岛。但是黑恶势力不会让玩家轻易得逞,他会把一些玩家抓走改造成僵尸。变成僵尸的玩家会攻击其他的玩家,被攻击的玩家会被”感染”,成为病毒的潜在宿主。
具体来说,游戏开始时,所有的玩家会获得一个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 。

来源/分类

江西OI2018 

[提交] [状态]

【总结】纸老虎

【分析】

这题有一个关键点,当我注意到时,才想明白此题:被感染的人也可以继续被选中,但被选中过的已经变成僵尸,不能选。

考虑这样一种数,我称为good数:在序列L,R中,不存在因子。也就是要想干掉good数,只能通过直接选中把它变成僵尸。

既然是等概率选僵尸,并且每个数只有一次机会,所以所有选择顺序情况就是L~R的全排列种情况。

而本题答案要求最终期望乘以(R-L+1)!,所以就变成了求 所有情况下,轮次的总和。

而对于一个排列的轮次就是,最后一个good数的位置。

1.预处理阶乘和阶乘的逆元,并且利用筛选法计算good数数量。(类似于素数筛选法)

2.枚举轮次,若某种排列进行i轮,则第i个位置一定最后一个good数,那么前i-1个位置就要放good-1个good数,剩下的位置放普通数。

3.整理下上面的描述就是,对于i轮的排列数量 =C_{good}^{1}*C_{n-good}^{(i-1)-(good-1)}*(i-1)!*(n-i)!

优化的话,化简上式就好了,不再累赘

【代码】

/****
***author: winter2121
****/
#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define SI(i) scanf("%d",&i)
#define PI(i) printf("%d\n",i)
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int MAX=1e7+5;
const int INF=0x3f3f3f3f;
const double eps=1e-8;
int dir[9][2]={0,1,0,-1,1,0,-1,0, -1,-1,-1,1,1,-1,1,1};
template<class T>bool gmax(T &a,T b){return a<b?a=b,1:0;}
template<class T>bool gmin(T &a,T b){return a>b?a=b,1:0;}
template<class T>void gmod(T &a,T b){a=(a%mod+b)%mod;}

ll gcd(ll a,ll b){ while(b) b^=a^=b^=a%=b; return a;}
ll inv(ll b){return b==1?1:(mod-mod/b)*inv(mod%b)%mod;}

bool vis[MAX+5];
ll fac[MAX+5],finv[MAX+5];
int main()
{
    fac[0]=1;
    rep(i,1,MAX)fac[i]=fac[i-1]*i%mod;
    finv[MAX]=inv(fac[MAX]);
    for(int i=MAX-1;i>=0;i--)finv[i]=(i+1)*finv[i+1]%mod;
    int L,R,n,good=0;
    cin>>L>>R;
    n=R-L+1;
    rep(i,L,R)if(!vis[i])
    {
        good++;
        for(int j=i+i;j<=R;j+=i)vis[j]=true;
    }
    ll ans=0;
    rep(i,good,n)
    {
        ll res=good*fac[n-good]%mod * fac[i-1]%mod *finv[i-good]%mod;
        gmod(ans,res*i);
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/winter2121/article/details/81533003
UPC