zoukankan      html  css  js  c++  java
  • 『 Luogu P3205 』 HNOI2010 合唱队

    解题思路

    设置两个二维数组 $f$ 和 $g$,含义如下。

    $f[l][r]$ 表示在期望得到的队形中 $l ightarrow r$ 这段区间初始队形排列的方案数,并且最后一个加入进去的是第 $l$ 个人。

    $g[l][r]$ 表示在期望得到的队形中 $l ightarrow r$ 这段区间初始队形排列的方案数,并且最后一个加入进去的是第 $r$ 个人。

    那么可以看出来 $g[l][r]$ 可以从 $g[l][r-1]$ 跟新出来,$f[l][r]$ 可以从 $f[l+1][r]$ 跟新出来。

    大致可以分为下面四种情况:

    • 现在决策的这个人插到队伍的最左边,即当前这个人比前一个加入队列的要矮,针对 $f[l][r]$
      • 前一个排进去的人是在第 $l+1$ 的位置上,$f[l+1][r] ightarrow a[l]<a[l+1]$
      • 前一个排进去的人是在第 $r$ 的位置上,$g[l+1][r] ightarrow a[l]<a[r]$
    • 现在决策的这个人插到队伍的最右边,即当前这个人比前一个加入队列的要高,针对 $g[l][r]$
      • 前一个排进去的人是在第 $l$ 的位置上,$f[l][r-1] ightarrow a[r]>a[l]$
      • 前一个排进去的人是在第 $r-1$ 的位置上,$g[l][r-1] ightarrow a[r]>a[r-1]$

    根据上面的关系就可以写出状态转移方程

    记得要初始化 $l=r$ 的数组,还有就是枚举区间长度的时候从 $2$ 开始枚举,否则会改变 之前初始化的数组造成答案出错

    附上代码

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    const int maxn = 1003, HA = 19650827;
    int n, f[maxn][maxn], g[maxn][maxn], a[maxn];
    int main() {
        scanf("%d", &n);
        for(int i=1; i<=n; i++)
            scanf("%d", &a[i]);
        for(int i=1; i<=n; i++) f[i][i] = 1;
        static int r;
        for(int i=2; i<=n; i++) {
            for(int l=1; l+i-1<=n; l++) {
                r = l+i-1;
                f[l][r] = f[l+1][r] * (a[l]<a[l+1]) % HA + g[l+1][r] * (a[l]<a[r]) % HA;
                f[l][r] = f[l][r] % HA;
                g[l][r] = f[l][r-1] * (a[r]>a[l]) % HA + g[l][r-1] * (a[r]>a[r-1]) % HA;
                g[l][r] = g[l][r] % HA;
            }
        }
        printf("%d", (g[1][n]+f[1][n]) % HA);
    }
  • 相关阅读:
    课程设计之第二次冲刺----第一天
    第一个spring冲刺总结
    课程设计之第一次冲刺----第九天
    课程设计之第一次冲刺----第八天
    课程设计之第一次冲刺----第七天
    课程设计之第一次冲刺----第六天
    课程设计之第一次冲刺---第5天
    课程设计之第一次冲刺---第四天
    课程设计之第一次冲刺---第3天
    课程设计之第一次冲刺---第二天
  • 原文地址:https://www.cnblogs.com/bljfy/p/9572712.html
Copyright © 2011-2022 走看看