首页 > 其他分享 >[Coci2011]kamion 题解

[Coci2011]kamion 题解

时间:2024-10-24 22:00:00浏览次数:6  
标签:匹配 limits kamion 题解 sum Coci2011 括号 leq mint

前言

题目链接:Hydro & bzoj黑暗爆炸

题意简述

给你一张 \(n\) 个点 \(m\) 条边的有向图。有 \(p\) 种括号,每条边的边权可以是这 \(p\) 种括号中某一种的左括号或者右括号,也可以为空。问你有多少条从 \(1\) 开始到 \(n\) 的长度小于等于 \(k\) 的路径,满足括号匹配,或者剩余若干未配对的左括号。答案对 \(10007\) 取模。

\(2 \leq n \leq 50\),\(1 \leq m \leq n(n-1)\),\(1 \leq k \leq 50\),\(p = 26\)。

题目分析

一眼 DP。考虑状态,显然不可以把栈压到状态里,那我们干脆不记栈了,设 \(f_{i, u, v}\) 表示 \(u\) 到 \(v\),经过了恰好 \(i\) 条边,且此时栈为空的方案数。但是答案可以剩余左括号,所以不妨再记 \(h_{i, u, v}\) 表示栈中剩余若干未匹配的左括号,并且这些括号会一直留到最后。

这看起来十分正确,我们可以枚举中转点 \(w\),再枚举 \(u \rightarrow w\) 和 \(w \rightarrow v\) 分别经过了多少条边,两个子问题方案数累乘后做一遍累加即可:\(f_{i, u, v} = \sum \limits _ {w = 1} ^ n \sum \limits _ {t = 1} ^ {i - 1} f_{t, u, w} f_{i - t, w, v}\)。而 \(h\) 只不过是多了一种无用左括号的转移:\(g_{i, u, v} = \sum \limits _ {w \in \operatorname{out}(u)} g_{i - 1, w, v}\)。

事实上,这种做法存在「重复统计」的问题。具体来讲,如果一条路径形如 \(u {\tt ()()()} v\),会被 \(u {\color{red} \tt ()} w {\color{magenta} \tt ()()} v\)、\(u {\color{red} \tt ()()} w {\color{magenta} \tt ()} v\) 统计到。怎么解决呢?

事实上,回顾我们序列上的括号匹配问题,即「区间 DP」,同样存在这种重复统计。那我们是怎么去除呢?发现,只要保证转移的时候,是「第一次」进行某一个操作,例如,「第一次」放置一个矩形([CEOI2009] photo),就能够保证每一种情况只会被统计到一次(因为「第一次」是唯一的)。括号匹配的「第一次」便是「第一次」成为一个匹配的括号串。

区间上如此,图上亦如此。我们考虑枚举的中转点是「第一次」成为一个匹配的括号串的位置,也即,保证 \(u \rightarrow w\) 的路径两端是一对匹配上的括号(\(u\ \texttt{(...)}\ v\))。我们可以记一个 \(g_{i, u, v}\),和 \(f\) 定义类似,只不过保证 \(u \rightarrow v\) 的路径两端是一对匹配上的括号。这样,我们的 \(f\) 就能够通过 \(g\) 和 \(f\) 的路径拼接而来:\(f_{i, u, v} = \sum \limits _ {w = 1} ^ n \sum \limits _ {t = 1} ^ {\color{red} \mathbf{i}} g_{t, u, w} f_{i - t, w, v}\)。注意,此时 \(t\) 的上界是 \(i\),因为对于 \(u\ \texttt{(...)}\ v\) 本身就合法。当然,\(h\) 同样如此。

我们把目光聚焦在求出 \(g\) 身上。我们不难发现,如果把最外层的那对括号扒掉,不就剩下一个形如 \(f\) 的括号串了吗?所以,我们只需要在 \(f_{i - 2}\) 的基础上,外层包裹一对括号即可:\(g_{i, u, v} = \sum \limits _ {tp = 1} ^ {p} \sum \limits _ {(u', tp) \in \operatorname{out}(u)} \sum \limits _ {(v', tp) \in \operatorname{in}(v)} f_{i - 2, u', v'}\)。

答案没什么好说的,就是 \(\sum \limits _ {i = 0} ^ k h_{i, 1, n}\)。

时间复杂度 \(\Theta(kn^4 + k^2n^3) = \Theta(kn^3(n + k))\),空间复杂度 \(\Theta(kn^2)\)。

代码

#include <cstdio>

const int N = 51;

using mint = unsigned short;
const mint mod = 10007;
inline mint add(mint a, mint b) { return a >= mod - b ? a + b - mod : a + b; }
inline mint mul(mint a, mint b) { return int(a) * b % mod; }
inline void toadd(mint &a, mint b) { a = add(a, b); }

int n, m, k;
char out[N][N], in[N][N], op;
bool emp[N][N];

mint f[N][N][N], h[N][N][N], g[N][N][N];

signed main() {
    scanf("%d%d%d", &n, &m, &k);
    for (int u, v; m--; ) {
        scanf("%d%d", &u, &v);
        while ((op = getchar()) == ' ');
        if ('A' <= op && op <= 'Z') out[u][v] = op - 'A' + 'a';
        else if ('a' <= op && op <= 'z') in[u][v] = op;
        else emp[u][v] = true;
    }
    for (int i = 1; i <= n; ++i) f[0][i][i] = h[0][i][i] = 1;
    for (int i = 1; i <= k; ++i) {
        if (i >= 2) {
            for (int u = 1; u <= n; ++u)
            for (int $u = 1; $u <= n; ++$u) if (out[u][$u])
            for (int v = 1; v <= n; ++v)
            for (int $v = 1; $v <= n; ++$v) if (out[u][$u] == in[$v][v])
                toadd(g[i][u][v], f[i - 2][$u][$v]);
        }
        for (int w = 1; w <= n; ++w)
        for (int u = 1; u <= n; ++u)
        for (int v = 1; v <= n; ++v) {
            if (emp[u][w]) toadd(f[i][u][v], f[i - 1][w][v]);
            if (emp[u][w] || out[u][w]) toadd(h[i][u][v], h[i - 1][w][v]);
            for (int l = 1; l <= i; ++l) {
                toadd(f[i][u][v], mul(g[l][u][w], f[i - l][w][v]));
                toadd(h[i][u][v], mul(g[l][u][w], h[i - l][w][v]));
            }
        }
    }
    mint ans = 0;
    for (int i = 0; i <= k; ++i) toadd(ans, h[i][1][n]);
    printf("%hu", ans);
    return 0;
}

标签:匹配,limits,kamion,题解,sum,Coci2011,括号,leq,mint
From: https://www.cnblogs.com/XuYueming/p/18500393

相关文章

  • 题解:P3012 [USACO11FEB] Cowlphabet G
    [USACO11FEB]CowlphabetG题意有\(P\)种拼接方式,问由\(U\)个大写字母和\(L\)个小写字母合法组合的方案数。输出方案数对\(97654321\)取模的值。思路动态规划,还没有人写逆推方法,刚好我做的逆推。设\(f[i][j][z]\)表示一共有\(i\)个字母,其中\(j\)个为小写字母,......
  • 题解:CF2030C A TRUE Battle
    LuoguLink|CodeforcesLink\(\texttt{Describe}\)给一个长度为\(n\)的二进制序列,Alice和Bob在相邻两个0/1中间分别加\(\operatorname{or}\)或\(\operatorname{and}\)操作,优先级满足\(\operatorname{and}>\operatorname{or}\)。Alice希望最后运算的值为\(1\),Bo......
  • P8164 [JOI 2022 Final] 沙堡 2 题解
    DescriptionJOI君在沙滩上堆沙堡,他已经做好了一个沙堡,沙堡可以使用一个\(H\timesW\)的二维矩形表示,其被划分成若干个\(1\times1\)的小格子,格子高度互相不同。JOI君决定在沙堡上游走,他可以从任意一个点出发,向上下左右四个方向行走,必须满足他行走的路径单调下降。出于一......
  • 题解:Maximum AND
    ProblemLinkMaximumAND题外话用sort肘过去了?题面翻译给定数组\(a\)和\(b\),重排\(b\)数组,求\(a_i\oplusb_i\)之后与和的最大值。Solution不难想到按位贪心。从最高位开始,逐位讨论是否能为\(1\)。接下来有一个做法:先将\(a\)数组升序排序,\(b\)数组降序排......
  • AtCoder Regular Contest 185 题解
    A-modMGame2第一个观察是如果一个人手中还有2张牌,那么他一定不会被秒。这可以推出决定胜负的时刻一定是Alice和Bob手中只剩一张牌的时候,此时如果Alice被秒了,那么她就似了,否则她就赢了。考虑Alice什么时候能被秒。记决定胜负的时刻Alice手中的牌是\(a\),Bob手......
  • 23~24 炼石计划 NOIP 练习题部分题解
    目录目录第1组JOISC2017火车旅行IOI2018会议CF1558FStrangeSortAPIO2018新家CTSC2017密钥CF1748EYetAnotherArrayCountingProblem第2组NOI2016区间LOJ552MIN&MAXIJOISC2023合唱LOJ542序列划分LOJ560Menci的序列P8978中位数第3组USACO20FEBHelpYourse......
  • CF35C. Fire Again 题解 bfs求最短路
    题目链接:https://codeforces.com/problemset/problem/35/C视频讲解:https://www.bilibili.com/video/BV1tZ1FYPELp/?p=4以每个着火的点为起点求最短路,然后输出任意一个距离值最大的点即可。需要注意的是:本题是文件输入输出。示例程序:#include<bits/stdc++.h>usingnamespace......
  • CF1139C. Edgy Trees 题解 并查集
    题目链接:https://codeforces.com/problemset/problem/1139/C视频讲解:https://www.bilibili.com/video/BV1tZ1FYPELp?p=3我们可以求总方案数-不满足条件的方案数。设一个不包含黑色边的极大连通块的大小为\(sz_i\)。则答案为\[n^k-\sum\{sz_i^k\}\]示例程序:#include......
  • CF1800E2. Unforgivable Curse (hard version) 题解 并查集
    题目链接:https://codeforces.com/contest/1800/problem/E2视频讲解:https://www.bilibili.com/video/BV1tZ1FYPELp?p=2把下标\(i\)对应到图中编号为\(i\)的节点。节点\(i\)和\(i+k\)之间连一条边,节点\(i\)和\(i+k+1\)之间也连一条边。同一个连通块里的节点对应的字......
  • P5661 [CSP-J2019] 公交换乘 题解
    模拟"公交换乘"按题意模拟即可.注意:可以使用结构体,但是超过时间的优惠券需要被忽略.代码#include<iostream>#include<cstdio>usingnamespacestd;structnode{ intprice,deadline,is_use;//价格,截止时间,是否使用过}a[100005];intn,p,ans,pos=1;int......