[思路题][洛谷P4609][FJOI2016]建筑师:组合数学

分析:

一道很不套路的题,暴力DP就不说了(反正也过不了)。
以下内容转自洛谷用户星沐的题解:

思路:
把最高的楼k当做分水岭,剩下的部分,从左边看到的是前缀max,从右侧看到的是后缀max。(感谢叶学长),左边除去最高楼k有A—1个,右边除去最高楼k有B—1个,然后分成A+B-2的圆排列,A+B-2每栋楼可放左边也可放右边,再组合一下
(引用叶学长的话说,剩下的A+B-2个,先决定放在n的左边还是右边。然后,将每个圆排列的将最大值钦定为所在方向(左或右)上的第一个,并以此为关键字将圆排列排序后放置。)

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
typedef long long LL;

inline int read(){
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x;
}

const LL MOD=1e9+7;
int n,A,B;
LL c[205][205],str1[50005][205];

inline void pre_process(){
    c[0][0]=1;
    for(int i=1;i<=200;i++)
        for(int j=0;j<=i;j++){
            c[i][j]=c[i-1][j];
            if(j) c[i][j]=(c[i][j]+c[i-1][j-1])%MOD;
        }
    str1[0][0]=1;
    for(int i=1;i<=50000;i++)
        for(int j=1;j<=200;j++)
            str1[i][j]=(str1[i-1][j-1]+str1[i-1][j]*(i-1))%MOD;
}

int main(){
    int T=read();
    pre_process();
    while(T--){
        n=read(),A=read(),B=read();
        printf("%lld\n",str1[n-1][A+B-2]*c[A+B-2][A-1]%MOD);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/9749022.html
今日推荐