• 【Luogu P3205】[HNOI2010]合唱队


    链接:

    洛谷

    题目大意:

    (n) 个人,每个人有一个高度 (h_i),从左到右按以下原则依次将每个人插入:

    • 第一个人直接插入空的当前队形中。
    • 对从第二个人开始的每个人,如果他比前面那个人高((h) 较大),那么将他插入当前队形的最右边。如果他比前面那个人矮((h) 较小),那么将他插入当前队形的最左边。

    求最后排成一个给定顺序的初始队列数。

    正文:

    像这种在左边右边插入的,可以考虑倒着处理,设 (f_{i,j,0/1}) 表示当前处理到区间 ([i,j]),且最后插入的数是插在了左边(或右边)。可以得到:

    [egin{aligned}f_{i,j,0}leftarrow left{egin{matrix}f_{i+1,j,0}&(h_i<h_{i+1})\ f_{i+1,j,1}&(h_i<h_j) end{matrix} ight.\ f_{i,j,1}leftarrow left{egin{matrix}f_{i,j-1,0}&(h_j>h_{i})\ f_{i,j-1,1}&(h_j>h_{j-1}) end{matrix} ight.\ end{aligned}]

    初值只用在 (f_{i,i,0/1}) 中任选一个变为 (1) 就好了。

    代码:

    const int N = 1010;
    const int mod = 19650827;
    
    inline ll Read()
    {
    	ll x = 0, f = 1;
    	char c = getchar();
    	while (c != '-' && (c < '0' || c > '9')) c = getchar();
    	if (c == '-') f = -f, c = getchar();
    	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    	return x * f;
    }
    
    int n;
    int a[N];
    int f[N][N][2];
    
    int main()
    {
    //	freopen(".in", "r", stdin);
    //	freopen(".out", "w", stdout);
    	n = Read();
    	for (int i = 1; i <= n; i++) a[i] = Read(), f[i][i][0] = 1;
    	for (int i = n; i; i--)
    		for (int j = i + 1; j <= n; j++)
    		{
    			if (a[i] < a[i + 1]) (f[i][j][0] += f[i + 1][j][0]) %= mod;
    			if (a[i] < a[j]) (f[i][j][0] += f[i + 1][j][1]) %= mod;
    			if (a[j] > a[i]) (f[i][j][1] += f[i][j - 1][0]) %= mod;
    			if (a[j] > a[j - 1]) (f[i][j][1] += f[i][j - 1][1]) %= mod;
    		}
    	printf ("%d
    ", (f[1][n][0] + f[1][n][1]) % mod);
    	return 0;
    }
    
    
  • 相关阅读:
    3.18 每日一练
    第二章 练习
    第一章 练习
    Redis常用操作大全和Python操作Redis
    vue学习【第七篇】:Vue之导入Bootstrap
    Vue学习【第六篇】:Vue-cli脚手架(框架)与实战案例
    Redis 安装,配置以及数据操作
    vue学习【第五篇】:Vue组件
    vue学习【第三篇】:vue之node.js的简单介绍
    Vue学习【第二篇】:ES6简单介绍
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/15429110.html
Copyright © 2020-2023  润新知