$("head").append('')

题解: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;//好习惯不能忘
}

posted @ 2025-10-27 11:13  lain_yc  阅读(2)  评论(0)    收藏  举报
$("head").append('')