zoukankan      html  css  js  c++  java
  • [洛谷P4609][FJOI2016]建筑师(第一类斯特林数)

    Solution

    • 首先,考虑最高的建筑\(n\),它一定是从左边看到的最后一个,也是从右边看到的最后一个
    • 剩下左边看到的\(A-1\)和右边看到的\(B-1\)
    • 考虑将剩下的\(n-1\)个建筑分成\(A+B-2\)个集合
    • 从中选出\(A-1\)个集合,将这些集合中的建筑放在\(n\)的左边,剩下的放右边
    • \(A-1\)个集合中,同一集合中的建筑在数轴上必为连续的一段
    • 记每个集合中最高的建筑(就是从左边看到的建筑)分别为\(c_1,c_2,...,c_{A-1}\),那么这\(A-1\)个建筑均位于每一段的最左边
    • 又因为它们都是被看见的(即不能相互遮挡)
    • 所以这\(A-1\)段按照\(c\)升序从左往右摆放
    • 右边的\(B-1\)段同理
    • 答案即\(S(n-1,A+B-2)*C(A+B-2,A-1)\)
    • 其中\(S\)是第一类斯特林数,表示\(n-1\)个数分成\(A+B-2\)个圆排列(无序)的方案数(因为确定了每段的开头是最高的建筑,圆排列也可以看作固定了开头的排列)

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    
    template <class t>
    inline void read(t & res)
    {
    	char ch;
    	while (ch = getchar(), !isdigit(ch));
    	res = ch ^ 48;
    	while (ch = getchar(), isdigit(ch))
    	res = res * 10 + (ch ^ 48);
    }
    
    const int mod = 1e9 + 7, e = 50005, o = 105;
    int s[e][o * 2], a, b, n, c[o * 2][o * 2], tst;
    
    int main()
    {
    	int i, j, k;
    	s[0][0] = c[0][0] = s[1][1] = 1; 
    	for (i = 2; i <= 50000; i++)
    	for (j = 1, k = min(i, 200); j <= k; j++)
    	s[i][j] = (s[i - 1][j - 1] + (ll)s[i - 1][j] * (i - 1)) % mod;
    	for (i = 1; i <= 200; i++)
    	for (j = 0; j <= i; j++)
    	if (j == 0) c[i][j] = 1;
    	else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
    	read(tst);
    	while (tst--)
    	{
    		read(n);
    		read(a);
    		read(b);
    		int ans = (ll)s[n - 1][a + b - 2] * c[a + b - 2][a - 1] % mod;
    		printf("%d\n", ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    实验0 了解和熟悉操作系统
    学习进度条
    0302软件构建与教学
    评论任务
    学习进度条
    sprint3个人总结
    软件工程学期总结
    6.3 学术诚信与职业道德
    阅读《构建之法》第8、9、10章
    nodejs学习心得
  • 原文地址:https://www.cnblogs.com/cyf32768/p/12196358.html
Copyright © 2011-2022 走看看