【2020/11/6每日一题】金字塔

金字塔
https://ac.nowcoder.com/acm/problem/51172

problem

金字塔由若干房间组成,房间之间连有通道。如果把房间看作节点,通道看作边的话,整个金字塔呈现一个有根树结构,节点的子树之间有序,金字塔有唯一的一个入口通向树根。并且,每个房间的墙壁都涂有若干种颜色的一种。探险队员打算进一步了解金字塔的结构,为此,他们使用了一种特殊设计的机器人。这种机器人会从入口进入金字塔,之后对金字塔进行深度优先遍历。机器人每进入一个房间(无论是第一次进入还是返回),都会记录这个房间的颜色。最后,机器人会从入口退出金字塔。显然,机器人会访问每个房间至少一次,并且穿越每条通道恰好两次(两个方向各一次), 然后,机器人会得到一个颜色序列。但是,探险队员发现这个颜色序列并不能唯一确定金字塔的结构。现在他们想请你帮助他们计算,对于一个给定的颜色序列,有多少种可能的结构会得到这个序列。因为结果可能会非常大,你只需要输出答案对 10^9 取模之后的值。

idea

例如 ABABABA 答案 5

输入是一个回文串,如果不是回文串,肯定方法数是0。

既然要分方法数,那么肯定就和递推或者动态规划有关系。并且数据量肯定满足动态规划。我们思考一下如果这棵树分为几个叉,那么几个叉的方法数肯定就是一个乘积的关系,一个复杂的问题分为多个步骤来完成。

分成几叉的条件是什么,就是在中间出现和根相同的字符,这个条件在题目中尤为重要。所以,这道题的代码就是一个基本的区间 dp 模板。也是区间dp求方法数。

我们以区间长度作为阶段,F[l,r] 表示序列 s[l~r] 中子树的个数。

如果我们从 l 到 r 在每一个点划分一个 k ,那么时间复杂度会很高。一个比较好的想法是,把子串 分成两部分,每部分可由若干子树构成。为了计数重而不漏,我们只考虑子串的第一颗子树是由哪些序列构成的即令子串 构成第一棵子树 构成剩余部分

为什么还要加上一个 F[l+1,r-1] 呢?因为我们虽然枚举了第一颗子树,但是却忽略了该树只有一颗子树的情况,所以需要再加上这种情况。

summery

对于方案计数类的动态规划问题,通常一个状态的各个决策之间满足“加法原理”,而每个决策划分的几个子状态之间满足“乘法原理”。在设计状态转移方程的决策方式与划分方法时,一个状态的所有决策之间必须具有互斥性,才能保证不会出现重复问题。

code

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 309;
const int mod = 1e9;
int f[maxn][maxn];
char a[maxn];
int32_t main() {
    cin >> a + 1;
    int len = strlen(a + 1);
    for (int i = 1; i <= len; i++) f[i][i] = 1;

    for (int l = 2; l <= len; l++)
        for (int i = 1; i + l - 1 <= len; i++) {
            int j = i + l - 1;
            if (a[i] != a[j]) continue;
            f[i][j] += f[i + 1][j - 1];
            for (int k = i + 1; k <= j - 1; k++)
                if (a[k] == a[i])
                    f[i][j] = (f[i][j] + f[i + 1][k - 1] * f[k][j] % mod) % mod;
        }
    cout << f[1][len];
    return 0;
}
全部评论

相关推荐

重生我想学测开:嵌入式的问题,我准备入行京东外卖了
点赞 评论 收藏
分享
评论
2
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务