【题解】White, Black and White Again [CF306C]

【题解】White, Black and White Again [CF306C]

传送门:\(\text{White, Black and White Again}\) \(\text{[CF306C]}\)

【题目描述】

\(n\) 个盒子排成一行,\(w\) 个互不相同的好球,\(b\) 个互不相同的坏球,现要将球全部放入盒子中,并满足从左到右依次为:若干好球、若干坏球、若干好球。每个盒子只能放一种类型的球且盒子不能为空。

【分析】

考虑最 \(naive\) 的想法:依次枚举放好球的盒子数量 \(i\)

将坏球视作一个整体,可以插在好球的中间,有 \(i-1\) 种方案。

\(w\) 个好球划分到 \(i\) 个盒子中,相当于一个插板问题,有 \(C_{w-1}^{i-1}\) 种方案,坏球同理,将 \(b\) 个坏球划分到 \(b-i\) 个盒子中,有 \(C_{b-1}^{n-i-1}\) 种方案。

最后再乘上 \(w!\) 以及 \(b!\),则答案为 \(w!b!\sum_{i=2}^{n-1}(i-1)C_{w-1}^{i-1}C_{b-1}^{n-i-1}\)

时间复杂度为 \(O(n\log{n})\) 或者 \(O(n)\),已经可以轻松跑过了,现在考虑能不能优化。

先推一波柿子:

\[ans=w!b!\sum_{i=2}^{n-1}(i-1)C_{w-1}^{i-1}C_{b-1}^{n-i-1}\]

\(mC_{n}^{m}=nC_{n-1}^{m-1}\) 得:

\[ans=w!b!(w-1)\sum_{i=2}^{n-1}C_{w-2}^{i-2}C_{b-1}^{n-i-1}\]

改变 \(i\) 的枚举方式得:

\[ans=w!b!(w-1)\sum_{i=0}^{n-3}C_{w-2}^{i}C_{b-1}^{n-3-i}\]

由范德蒙德卷积 \(\sum_{i=0}^{k} C_{n}^{i} C_{m}^{k-i}=C_{n+m}^{k}\) 得:

\[ans=w!b!(w-1)C_{w+b-3}^{n-3}\]

现在查询变成 \(O(1)\) 或者 \(O(\log{n})\) 了。

那么这个式子又应该如何理解呢?

由于球的排列方式一定是 “好...好....坏...坏...好...好”,考虑直接将 \(w+b\) 个球分配到 \(n\) 个盒子中,即在 \(w+b-1\) 个空隙中插入 \(n-1\) 块板子。但由于好坏球之间必定会有 \(2\) 块固定的板子(由好坏球个数决定,在一次询问中球数是已知的),所以相当于在 \(w+b-3\) 个空隙中插入 \(n-3\) 块板子,方案数为 \(C_{w+b-3}^{n-3}\) 。由于坏球的位置依旧不确定,所以要乘上 \(w-1\)。最后再乘以 \(w!b!\) 即为答案。

注意模数别看错了,是 \(10^9+9\) 不是 \(10^9+7\)\(\text{CF}\) 总喜欢搞一些近似模数来坑你。

【Code】

#include<algorithm>
#include<cstring>
#include<cstdio>
#define LL long long
#define Re register int
using namespace std;
const int N=4003,P=1e9+9;
int n,w,b,jc[N<<1];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline int mi(Re x,Re k){
    Re s=1;
    while(k){
        if(k&1)s=(LL)s*x%P;
        x=(LL)x*x%P,k>>=1;
    }
    return s;
}
inline int inv(Re x){return x==0?1:mi(x,P-2);}
inline int C(Re m,Re n){return (LL)jc[n]*inv(jc[n-m])%P*inv(jc[m])%P;}
int main(){
//  freopen("123.txt","r",stdin);
    in(n),in(w),in(b),jc[0]=1;
    for(Re i=1;i<=w+b;++i)jc[i]=(LL)jc[i-1]*i%P;
//  Re ans=0;
//  for(Re i=max(n-b,2);i<=n-1&&i<=w;++i)
//      (ans+=(LL)C(i-1,w-1)*C(n-i-1,b-1)%P*(i-1)%P)%=P;
//  printf("%d\n",(LL)ans*jc[w]%P*jc[b]%P);
    printf("%d\n",(LL)C(n-3,w+b-3)*(w-1)%P*jc[w]%P*jc[b]%P);
}

猜你喜欢

转载自www.cnblogs.com/Xing-Ling/p/12453851.html