题目
问有多少个1∼n1\sim n1∼n的排列,满足从左边只走上坡能看到aaa个数,从右边只走上坡能看到bbb个数
分析
那么先把最高值分开,那么左边有a−1a-1a−1个,右边有b−1b-1b−1个,那么共有a+b−2a+b-2a+b−2个,而样子类似合唱队形还可以旋转,所以其实就是在n−1n-1n−1个数中坐在a+b−2a+b-2a+b−2个圆桌的方案数,再选择a+b−2a+b-2a+b−2个数中选择a−1a-1a−1个放左边,那么总而言之,答案就是
C(a+b−2,a−1)∗Stirling(n−1,a+b−2)C(a+b-2,a-1)*Stirling(n-1,a+b-2)C(a+b−2,a−1)∗Stirling(n−1,a+b−2),后面是第一类斯特林数,时间复杂度O(na+T)O(na+T)O(na+T)
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=50001,M=201,mod=1e9+7;
int stir[N][M],c[M][M];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
signed main(){
stir[0][0]=c[0][0]=1;
for (rr int i=1;i<N;++i)
for (rr int j=1;j<=i&&j<M;++j)
stir[i][j]=mo(stir[i-1][j-1],1ll*(i-1)*stir[i-1][j]%mod);
for (rr int i=1;i<M;++i){
c[i][0]=1;
for (rr int j=1;j<=i;++j)
c[i][j]=mo(c[i-1][j],c[i-1][j-1]);
}
for (rr int t=iut();t;--t){
rr int n=iut(),a=iut(),b=iut();
print(1ll*stir[n-1][a+b-2]*c[a+b-2][a-1]%mod),putchar(10);
}
return 0;
}

博客讨论了洛谷4609题目的建筑师问题,涉及排列组合中上坡可视数的概念。通过分析得出,解决该问题的关键在于计算在n-1个数中安排a+b-2个圆桌的方案数,并结合第一类斯特林数,最终时间复杂度为O(na+T)。

被折叠的 条评论
为什么被折叠?



