【FJOI2016】建筑师

安利另外一篇(blog)

密码泥萌都知道

题面

题解

为了描述方便,这里将建筑称作(zsy)

高度为(n)(zsy)无论如何都能从左右两侧看到。剩下的部分,从左边看到的是前缀(max),从右侧看到的是后缀(max)。大概像这样:

gsy

对于被框住的(A+B−1)个部分,只有第一个能作为前、后缀(max)被看到。可以认为是把数分成(A+B−1)个圆排列,其中有一个仅包含(n)。剩下的(A+B−2)个,先决定放在(n)的左边还是右边。然后,将每个圆排列的将最大值钦定为所在方向(左或右)上的第一个,并以此为关键字将圆排列排序后放置。

所以对于一组询问,答案就是:

[egin{bmatrix}n-1\A+B-2end{bmatrix} imesinom{A+B-2}{A-1} ]

代码

#include<bits/stdc++.h>
#define RG register
#define clear(x, y) memset(x, y, sizeof(x));
using namespace std;

inline int read()
{
    int data=0, w=1;
    char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') w=-1, ch=getchar();
    while(ch>='0'&&ch<='9') data=data*10+(ch^48), ch=getchar();
    return data*w;
}

const int mod(1e9 + 7), maxn(50010), maxk(210), K(201);
int T, n, A, B, C[maxk][maxk], S[maxn][maxk];

inline void Init()
{
    C[0][0] = 1;
    for(RG int i = 1; i <= K; i++)
    {
        C[i][0] = C[i][i] = 1;
        for(RG int j = 1; j < i; j++) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
    }
    for(RG int i = 0; i <= K; i++) S[i][i] = 1;
    for(RG int i = 2; i <= maxn - 10; i++)
        for(RG int j = 1; j < i && j <= K; j++)
            S[i][j] = (1ll * (i - 1) * S[i - 1][j] % mod + S[i - 1][j - 1]) % mod;
}

int main()
{
    T = read(); Init();
    while(T--)
    {
        n = read(); A = read(); B = read();
        if(A + B > n + 1) { puts("0"); continue; }
        printf("%lld
", 1ll * C[A + B - 2][A - 1] * S[n - 1][A + B - 2] % mod);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cj-xxz/p/10280398.html