题解:P6026 餐馆
P6026 餐馆
题目背景
小 W 家新开了一家餐馆。
题目描述
这家餐馆提供 \(n\) 种特色菜,它们被标号为 \(1,2,\cdots,n\)。
有一天,餐馆里来了 \(k\) 个客人,他们没有想好要吃什么。于是,小 W 给他们出了个主意:每个人先从 \(1,2,\cdots,n\) 中等概率随机一个数 \(r\),再从
\(1,2,\cdots,r\) 中等概率随机一个数 \(l\),这个人就点标号在 \(l\) 和 \(r\) 之间(包括 \(l\) 和 \(r\))的菜。
于是,客人们按小 W 说的做了。在所有客人都点完单之后,小 W 突然发现:没有两个人都点了相同的一道菜,他每种菜至多做一份就够了!为了证明他是多么的欧皇,他找到了学编程的你,请你帮他计算这种情况发生的概率。
输入格式
两个整数 \(n\) 和 \(k\),意义如题目描述。
输出格式
一个整数 \(p\),表示所求概率对 \(10^9+7\) 取模后的结果。
输入输出样例 #1
输入 #1
10 1
输出 #1
1
输入输出样例 #2
输入 #2
2 2
输出 #2
250000002
说明/提示
样例解释:
样例 \(1\) 解释:因为只有一位客人,所以无论如何不会有两个人点同样的菜,故所求概率为 \(1\)。
样例 \(2\) 解释:每位客人只点 \(1\) 号菜的概率为 \(\dfrac12\),只点 \(2\) 号菜的概率为 \(\dfrac14\),两个菜都点的概率为 \(\dfrac14\),两人不点同一道菜即一人只点 \(1\) 号菜,一人只点 \(2\) 号菜,概率为
\(\dfrac14\times\dfrac12+\dfrac12\times\dfrac14=\dfrac14\),模 \(10^9+7\) 意义下为
\(250000002\)。
提示:如果你不知道如何对有理数取余,请看 P2613。
数据范围:
对于 \(10\%\) 的数据, \(k=1\)。
对于另外 \(10\%\) 的数据, \(1\le k\le n\le5\)。
对于另外 \(20\%\) 的数据, \(1\le k\le3\)。
对于另外 \(30\%\) 的数据, \(1\le k\le n\le10^3\)。
对于所有数据, \(1\le k\le n\le 10^8\)。
题解
前置知识:快速幂,组合数学,有理数取余
题意:
对于一个区间 \([1,n]\),有 \(k\) 次选择,每次选择区间 \([l,r]\),其中 \(r\in[1,n],l\in[1,r]\)。求所有选择均无重叠区间的期望。
手玩:
特别的:由鸽笼原理可得,\(n<k\) 的时候怎么选都会至少有一个重复,因此答案为 \(0\)。
我们把 \(k\) 作为分类的标准,可以发现:
-
当 \(k=1\) 时:无论 \(n\) 取多少,答案都是 \(1\),因为一个区间不存在重合这一说。
-
当 \(k≥2\) 时:因为两次选择分别在 \([1,n]\) 和 \([1,r]\),因此对于一个 \([l,r]\) 的区间,被选中的概率是 \(\frac{1}{n\times r}\)。既然这样,我们不妨来列一下 \(k=2\) 时所有情况及概率:
| 选择的数 | 概率 |
|---|---|
| \(1\) | \(\frac{1}{2}\) |
| \(2\) | \(\frac{1}{4}\) |
| \(1,2\) | \(\frac{1}{4}\) |
显然,当第一次选择 \(1\) 时,第二次只能选择 \(2\),反之亦然,而无论哪次都不能选择 \(1,2\)。因此,\(n=2,k=2\) 的时候答案是 \(\frac{1}{2\times4}+\frac{1}{2\times4}=\frac{1}{4}\)。
这样,我们可以手推得到:
| 概率 | \(n=2\) | \(n=3\) | \(n=4\) | \(n=5\) | \(n=6\) |
|---|---|---|---|---|---|
| \(k=2\) | \(\frac{1}{4}\) | \(\frac{1}{3}\) | \(\frac{3}{8}\) | \(\frac{2}{5}\) | \(\frac{5}{12}\) |
如果这样不好找规律的话,反约分一下呢?
| 概率 | \(n=2\) | \(n=3\) | \(n=4\) | \(n=5\) | \(n=6\) |
|---|---|---|---|---|---|
| \(k=2\) | \(\frac{1}{4}\) | \(\frac{3}{9}\) | \(\frac{6}{16}\) | \(\frac{10}{25}\) | \(\frac{15}{36}\) |
似乎有规律了!但是,先别急着写代码,来试试 \(k=3\) 的情况:
| 概率 | \(n=1\) | \(n=2\) | \(n=3\) | \(n=4\) |
|---|---|---|---|---|
| \(k=3\) | \(\frac{0}{1}\) | \(\frac{0}{8}\) | \(\frac{1}{27}\) | \(\frac{4}{64}\) |
此时,我们可以感性理解一下:
由于要从 \(n\) 个里面取 \(k\) 轮,所以说大概率有一个 \(C_n^k\) 同时观察分母,不难发现是 \(\frac{1}{n^k}\)。那么分子上的
\(1,3,6,10,15\)……
和
\(1,4,10\)……
正好等于 \(C_n^k\)。于是我们就用数学归纳法得到了 \(f(n,k)=\frac{C_n^k}{n^k}\) (其实是蒟蒻不会证喵)
实现:
既然有了公式了,实现就很简单了:
先线性处理 \(n!,k!,(n-k)!\) 以此计算 \(C_n^k\),然后计算 \(n^k\) 的逆元最后再乘起来就好了~
警示后人:
开 \(long long\),勤取模!
AC 代码
#include<bits/stdc++.h>
using namespace std;
long long n,k,kj=1,nkj=1,jc=1,ans;
//kj,nkj,jc分别是k,(n-k),n的阶乘
const int mod=1e9+7;
long long qpow(long long a,long long b,long long mod){
a%=mod;
long long ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>k;
if(n<k){
cout<<0;
return 0;
//特判
}
for(int i=2;i<=n;i++){
jc*=i;jc%=mod;
if(i==k)kj=jc;
if(i==(n-k))nkj=jc;
}
long long invk=(kj*nkj)%mod;
invk=qpow(invk,mod-2,mod);
invk=(invk*jc)%mod;
if(n==k)invk=1;
long long invn=qpow(qpow(n,k,mod),mod-2,mod);
ans=(invk*invn)%mod;
cout<<ans;
return 0;//好习惯不能忘
}

浙公网安备 33010602011771号