p4609 [FJOI2016]建筑师

题面:https://www.luogu.org/problemnew/show/P4609

考虑先把最大值放了以后,左边a-1个圆排列,右边b-1个圆排列。
直接就是C(a-1+b-1,a-1)*S(n-1,a-1+b-1)。
S为第一类斯特林数。

#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#define N 55000
#define M 220
#define eps 1e-7
#define inf 1e9+7
#define db double
#define ll long long
#define ldb long double
using namespace std;
inline ll read()
{
    char ch=0;
    ll x=0,flag=1;
    while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*flag;
}
const ll mo=1e9+7;
ll fac[N],vac[N],s[N][M];
ll c(ll n,ll m){return fac[n]*vac[m]%mo*vac[n-m]%mo;}
ll ksm(ll x,ll k){ll ans=1;while(k){if(k&1)ans=ans*x%mo;k>>=1;x=x*x%mo;}return ans;}
void work()
{
    ll n=read(),a=read(),b=read();
    if(a+b>n+1)printf("0\n");
    else printf("%lld\n",(c(a-1+b-1,a-1)*s[n-1][a-1+b-1])%mo);
}
int main()
{
    fac[0]=vac[0]=s[0][0]=1;
    for(ll i=1;i<=50000;i++)
    {
        fac[i]=fac[i-1]*i%mo;
        vac[i]=vac[i-1]*ksm(i,mo-2)%mo;
        for(ll j=1;j<=200;j++)
        s[i][j]=((s[i-1][j]*(i-1)%mo)+s[i-1][j-1])%mo;
    }
    ll t=read();
    for(ll i=1;i<=t;i++)work();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Creed-qwq/p/10618909.html
今日推荐