题解:
题目要求是有序的排列,因此我们可以在一开始就乘上A!*B!然后在把这个序列划分成很多段。
这样的话由于乘了阶乘,所以所有排列我们都已经统计到了,因为划分段的时候乘了组合数,所以每段里面的不同排列都已经统计到了,所以就可以解决这道题了。
主要难度在与平时我们计算方案时一般都是先划分,再乘阶乘,所以如果陷入这个误区就可能做不出来了。
所以我们先枚举中间那段有多长,然后乘一下阶乘和处理划分的组合数,最后再乘一下中间这段的第一个可以放在多少个位置。
因为左右两段都必须非空,所以左边要预留一位,所以第一个可以放的位置在2,同理,最后一个可以放的位置在n - i.减一下就可以得到可以放在n - i - 1个位置。
注意一下枚举的时候中间的天数最多n - 2,原因同上
$ans = A! cdot B! cdot inom{A - 1}{n - i - 1} cdot inom{B - 1}{i - 1} cdot (n - i - 1)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 101000 5 #define p 1000000009 6 #define LL long long 7 8 LL A_ = 1, B_ = 1, A, B, t, all, ans; 9 LL C[2][AC], inv[AC]; 10 11 void cal(LL n, int x) 12 { 13 C[x][0] = 1; 14 for(R i = 1; i <= t; i ++) 15 C[x][i] = C[x][i - 1] * (n - i + 1) % p * inv[i] % p; 16 } 17 18 void pre() 19 { 20 scanf("%lld%lld%lld", &t, &A, &B); 21 inv[0] = inv[1] = 1; 22 for(R i = 2; i <= t; i ++) inv[i] = (p - p / i) * inv[p % i] % p; 23 for(R i = 2; i <= A; i ++) A_ = A_ * i % p; 24 for(R i = 2; i <= B; i ++) B_ = B_ * i % p; 25 cal(A - 1, 0), cal(B - 1, 1); 26 all = A_ * B_ % p; 27 } 28 29 void work() 30 { 31 int b = min(t - 2, B); 32 for(R i = 1; i <= b; i ++)//枚举中间的天数 33 ans = (ans + all * C[0][t - i - 1] % p * C[1][i - 1] % p * (t - i - 1) % p) % p; 34 printf("%lld ", ans); 35 } 36 37 int main() 38 { 39 freopen("in.in", "r", stdin); 40 pre(); 41 work(); 42 fclose(stdin); 43 return 0; 44 }