[FJOI2016]建筑师

LOJ

  • 一个长度为n的排列,从左向右最大值更新了A次,从右向左更新了B次。求方案数。
  • 画一张图:
    在这里插入图片描述
  • 画出的线段即为每一个max改变的峰。两峰之间可以插进去一些数。对于最高点左边的数来说,相当于每一个线段引领了一些数,这些数在它的右边,且都比他小。对于最高点右边的数来说,相当于每个右边的线段引领了一些数,这些数都在它的左边并且比他小。
  • 考虑转化其模型。每个线段+它引领的数,方案数相当于这若干个数组合一个圆的方案数。
  • 那这道题就相当于把 n − 1 n-1 n1个数分成了 A + B − 2 A+B-2 A+B2的圆排列,不过左边的 A − 1 A-1 A1个圆排列可以是任意挑出来的,所以乘上一个组合数。
    a n s = s [ n − 1 ] [ A + B − 2 ] ∗ C [ A + B − 2 ] [ A − 1 ] ans=s[n-1][A+B-2]*C[A+B-2][A-1] ans=s[n1][A+B2]C[A+B2][A1]
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 201;
const int M = 5e4 + 10;
const int mod = 1e9 + 7;
int t, n, a, b;
ll s[M][N], c[N][N];
int main() {
    scanf("%d", &t);
    s[0][0] = 1;
    for (int i = 1; i <= M - 10; ++i) {
        for (int j = 1; j <= min(N - 1, i); ++j) s[i][j] = (s[i - 1][j] * (i - 1) + s[i - 1][j - 1]) % mod;
    }
    c[0][0] = 1;
    for (int i = 1; i <= N - 1; ++i) {
        c[i][0] = 1;
        for (int j = 1; j <= min(N - 1, i); ++j) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
    }
    while (t--) {
        scanf("%d%d%d", &n, &a, &b);
        if (a + b > n + 1)
            printf("0\n");
        else
            printf("%lld\n", s[n - 1][a + b - 2] * c[a + b - 2][a - 1] % mod);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值