Atcoder CODE FESTIVAL 2017 qual B E

题目链接

题意

(A+B)个球排成一行,左边(A)个为红球,右边(B)个为蓝球。

最开始可以选择两个数(s,t),每次操作可以取左起第(1)(s)(t)个球。问有多少种不同的取球序列。

Sample

Sample Input 1

3 3

Sample Output 1

20

Explanation

There are 20 ways to give 3 red balls and 3 blue balls. It turns out that all of them are possible.

Here is an example of the operation (r stands for red, b stands for blue):

You choose s=3,t=4.
Initially, the row looks like rrrbbb.
You remove 3rd ball (r) and give it to Snuke. Now the row looks like rrbbb.
You remove 4th ball (b) and give it to Snuke. Now the row looks like rrbb.
You remove 1st ball (r) and give it to Snuke. Now the row looks like rbb.
You remove 3rd ball (b) and give it to Snuke. Now the row looks like rb.
You remove 1st ball (r) and give it to Snuke. Now the row looks like b.
You remove 1st ball (b) and give it to Snuke. Now the row is empty.
This way, Snuke receives balls in the order rbrbrb.

思路

官方题解

将剩下的球的序列转化成二维平面上的点,则取球过程为起点为((A,B)),终点为((0,0))的路径。

显然,可以一直向左走,因为向左走就对应着取该序列的第一个元素;

但是向下走是需要满足一定的条件的,那就是红球的个数小于(s)(t)中的某一个。

在阴影区域内可以随意向左走或向下走。

因此,可以枚举((p,q)),从((A,B))((p,q))的路径条数可以通过预处理组合数然后(O(1))算出,而从((p,q))((0,0))的路径条数可以预处理出。

(q-1=4)为例,

分界线为(x=0)时,有(inom{4}{0})种,
分界线为(x=1)时,有(inom{4}{0}+inom{4}{1})种,
分界线为(x=2)时,有(inom{4}{0}+inom{4}{1}+inom{4}{2})种,
分界线为(x=3)时,有(inom{4}{0}+inom{4}{1}+inom{4}{2}+inom{4}{3})种,
分界线为(x=4)时,有(inom{4}{0}+inom{4}{1}+inom{4}{2}+inom{4}{3}+inom{4}{4})种,
分界线为(x=5)时,有(inom{4}{0}+inom{4}{1}+inom{4}{2}+inom{4}{3}+inom{4}{4})种,
……
分界线为(x=n(ngeq 4))时,有(inom{4}{0}+inom{4}{1}+inom{4}{2}+inom{4}{3}+inom{4}{4})种.
对于((p,q)),将分界线为(x=0,1,2,...,p)的情况累和,即得路径条数。

Code

参考:

#include <bits/stdc++.h>
#define maxn 4000
#define maxm maxn+10
using namespace std;
typedef long long LL;
LL temp[maxm][maxm], C[maxm][maxm];
const LL mod = 1e9+7;
LL add(LL a, LL b) { return (a+b) % mod; }
LL mul(LL a, LL b) { return (a*b) % mod; }
void init() {
    for (int i = 0; i <= maxn; ++i) C[i][0] = 1;
    for (int i = 1; i <= maxn; ++i) {
        for (int j = 1; j <= i; ++j) C[i][j] = add(C[i-1][j], C[i-1][j-1]);
    }
    for (int i = 0; i <= maxn; ++i) {
        temp[i][0] = C[i][0];
        for (int j = 1; j <= maxn; ++j) {
            temp[i][j] = add(temp[i][j-1], C[i][j]);
        }
    }
    for (int i = 0; i <= maxn; ++i) {
        for (int j = 1; j <= maxn; ++j) temp[i][j] = add(temp[i][j], temp[i][j-1]);
    }
}
int main() {
    init();
    int a, b;
    LL ans = 0;
    scanf("%d%d", &a, &b);
    for (int p = 0; p <= a; ++p) {
        for (int q = 0; q <= b-1; ++q) {
            if (p+q > a) continue;
            if (q == 0) ans = add(ans, 1);
            else ans = add(ans, mul(C[b-1][q], temp[q-1][p]));
        }
    }
    printf("%lld
", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/kkkkahlua/p/7646240.html