洛谷 P3205 [HNOI2010]合唱队

题目传送门


思路:

对于理想队形中[l, r]的部分,它可以由第l个人从左边入队,也可以由第r个人从右边入队。

对于第l个人从左边入队的情况,可分为两种:上一个是第l+1个人从左端入队,则需满足h[l] < h[l+1];上一个是第r个人从右端入队,则需满足h[l] < h[r]。

对于第r个人从右边入队的情况则同理。

那么我们可以设f[i][j][k]表示从i到j的方案数,当k=0时,表示上一个入队的是第i个人,当k=1时,表示上一个入队的是第j个人。

根据上面的分析不难写出转移方程:

if(h[i] < h[i+1]) f[i][j][0] += f[i+1][j][0];
if(h[i] < h[j]) f[i][j][0] += f[i+1][j][1];
if(h[i] < h[j]) f[i][j][1] += f[i][j-1][0];
if(h[j] > h[j-1]) f[i][j][1] += f[i][j-1][1];

为了避免重复计算,所以预处理中我们只将所有的f[i][i][0]置为1即可。


Code:

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
//Mystery_Sky
//
#define M 10000100
#define INF 0x3f3f3f3f
#define ll long long
#define Mod 19650827
inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n;
int f[1001][1001][2], h[1001];
int main() {
    n = read();
    for(int i = 1; i <= n; i++) h[i] = read(), f[i][i][0] = 1;
    for(int len = 1; len <= n; len++) {
        for(int i = 1; i + len - 1 <= n; i++) {
            int j = i + len - 1;
            if(h[i] < h[i+1]) f[i][j][0] += f[i+1][j][0];
            if(h[i] < h[j]) f[i][j][0] += f[i+1][j][1];
            if(h[i] < h[j]) f[i][j][1] += f[i][j-1][0];
            if(h[j] > h[j-1]) f[i][j][1] += f[i][j-1][1];
            f[i][j][0] %= Mod, f[i][j][1] %= Mod;
        }
    }
    printf("%d\n", (f[1][n][0] + f[1][n][1]) % Mod);
    return 0;
} 

转载于:https://www.cnblogs.com/Benjamin-cpp/p/11443445.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值