CF306C White, Black and White Again
题目描述
Polycarpus is sure that his life fits the description: "first there is a white stripe, then a black one, then a white one again". So, Polycarpus is sure that this rule is going to fulfill during the next nn days. Polycarpus knows that he is in for ww good events and bb not-so-good events. At least one event is going to take place during each day. As each day is unequivocally characterizes as a part of a white or a black stripe, then each day is going to have events of the same type only (ether good or not-so-good).
What is the number of distinct ways this scenario can develop over the next nn days if Polycarpus is in for a white stripe (a stripe that has good events only, the stripe's length is at least 1 day), the a black stripe (a stripe that has not-so-good events only, the stripe's length is at least 1 day) and a white stripe again (a stripe that has good events only, the stripe's length is at least 1 day). Each of nn days will belong to one of the three stripes only.
Note that even the events of the same type are distinct from each other. Even if some events occur on the same day, they go in some order (there are no simultaneous events).
Write a code that prints the number of possible configurations to sort the events into days. See the samples for clarifications on which scenarios should be considered distinct. Print the answer modulo 10000000091000000009 (10^{9}+9)(109+9) .
输入格式
The single line of the input contains integers nn , ww and bb ( 3<=n<=40003<=n<=4000 , 2<=w<=40002<=w<=4000 , 1<=b<=40001<=b<=4000 ) — the number of days, the number of good events and the number of not-so-good events. It is guaranteed that w+b>=nw+b>=n .
输出格式
Print the required number of ways modulo 10000000091000000009 (10^{9}+9)(109+9) .
题意翻译
Polycarpus*Polycarpu**s* 的生活总是满足“一些好事,然后一些坏事,然后一些好事”这样的规律。
所以 Polycarpus*Polycarpu**s* 认为接下来的 nn 天也是满足这样的规律的。
Polycarpus*Polycarpu**s* 知道,接下来会发生 ww 件两两不同的好事和 bb 件两两不同坏事,每天至少发生一件事,每天要么全部发生好事要么全部发生坏事。
由于 Polycarpus*Polycarpu**s* 的规律,这 nn 天会先有若干天发生好事,再有若干天发生坏事,再有若干天发生好事(若干代指>0>0)。
要求统计事件发生的方案数(每天发生的事的顺序也不一样),答案取模 10^9+9109+9 输出。
输入输出样例
输入 #1复制
输出 #1复制
输入 #2复制
输出 #2复制
输入 #3复制
输出 #3复制
说明/提示
We'll represent the good events by numbers starting from 1 and the not-so-good events — by letters starting from 'a'. Vertical lines separate days.
In the first sample the possible ways are: "1|a|2" and "2|a|1". In the second sample the possible ways are: "1|a|b|2", "2|a|b|1", "1|b|a|2" and "2|b|a|1". In the third sample the possible ways are: "1|ab|2", "2|ab|1", "1|ba|2" and "2|ba|1".
题解:
2019.10.16模拟赛爆氮T1
题面翻译来发第一篇题解...
首先拿到这道题手推了几组数据。然后灵光一闪:有没有可能是这些事件的发生顺序和到底发生在哪天并没有关系?就是说:我只需要把\(w\)件好事和\(b\)件坏事排成一排,保证\(b\)件坏事全在中间,两头都有好事即可。
但是这样绝对是不行的,因为我们把这些事件拆分成很多天(当然是满足题意的拆分方法),就是很多种方案。
但是这样的一个思路却为我们打开了一个突破口:在这样一个前面是一堆好事、中间夹了一堆坏事、最后又是一堆好事的序列中,我们只需要“往里添几个分隔板”,表示天数的差异,再进行统计即可。
隆重介绍:排列组合常用切题法:隔板法。
高中数学的排列组合会讲到,但是本蒟蒻并没有学.....简单介绍一下,排成一行的\(n\)件事,我们需要在其中的\(n-1\)个“缝隙”中,填入\(m\)个隔板,这样就把整个序列划分成了\(m+1\)个部分。
那么,我们有多少种合法的添入隔板的方法,就有多少种可能的天数划分方法。至于每天的事件发生顺序有所不同,我们只需要把天数划分方法乘上\(w!\times b!\)即可。(全排列公式)
于是,我们得到了一个组合数的公式:将\(n\)件事中填入\(m\)个隔板(分成了\(m+1\)个部分),方式有:(种)
\[
C_{n-1}^{m}=\frac{(n-1)!}{m!(n-m-1)!}
\]
于是这道题就变成了一道组合数取模的题。
不要忘了最后要乘两个阶乘。因为数据范围已经给出,所以我们只需要考虑预处理出阶乘数组即可。
当然,也要顺道处理出乘法逆元的数组(除法取模要用)。
思路比较容易得出,但是不太容易理顺及证明正确性。而且代码的实现(取模)细节比较多,%……*&
代码如下:
#include<cstdio> #define ll long long #define mod 1000000009 using namespace std; const int maxn=4001; int fac[maxn],inv[maxn]; int n,w,b,ans; void init_fact() { fac[0]=1; for(int i=1;i<=maxn;i++) fac[i]=(ll)i*fac[i-1]%mod; } void init_inv() { inv[0]=1;inv[1]=1; for(int i=2;i<=maxn;i++) inv[i]=mod-(ll)(mod/i)*inv[mod%i]%mod; for(int i=1;i<=maxn;i++) inv[i]=(ll)inv[i-1]*inv[i]%mod; } int calc(int n,int m) { return (ll)fac[n]*inv[m]%mod*inv[n-m]%mod; } int main() { init_fact(); init_inv(); scanf("%d%d%d",&n,&w,&b); for(int i=1;i<=b;i++) if(n-i>=2 && n-i<=w) ans=((ll)ans+(ll)(n-i-1)*calc(b-1,i-1)%mod*calc(w-1,n-i-1)%mod)%mod; ans=(ll)((ll)ans*fac[w]%mod*fac[b]%mod)%mod; printf("%d",ans); return 0; }