记一次失败的比赛 + ABC214 F 题题解
1.前言
一次失败的比赛。首先为了赶时间(其实也就争取了10min左右),我尝试在出租车上打代码,下来差点吐了 \(qwq\),然后车上因为晕乎乎的,把 \(D\) 和 \(F\) 的题意读错了,把 \(D\) 取 \(max\) 读成了求和(然后还嘲讽出题人只会出换根 \(dp\) 板题,并大骂出题人不会出样例,浪费了 \(20min\) 左右),\(F\) 把不能留下连续的读成了不能删去连续的(然后就放弃 \(F\), 撞死在 \(E\) 题贪心上)。总之虽然外因很多,但主要原因还是自己太菜了呀~。 不久前已经开始记录自己认为的好题,时不时重做一下吧 (虽然可能会咕)
2.题解
悲伤的回味已经过去了,现在开始进入快乐的题解部分
容易想到 \(dp\)。
状态定义:
\(dp[i]\): 前 \(i\) 个字符中选,必选第 \(i\) 个字符,不与 \(s1\subseteq s_{[1,i)}\) 重复的满足要求的子序列个数。
状态转移:
1. \(\forall j \in [1,i),s[j] \neq s[i]\)
\(dp[i] = (\sum_{k = 1}^{i - 2}dp[k]) + 1\)
2. \(\exists j \in [1, i), s[j] = s[i]\)
令 \(p = \max j (j \in [1, i), s[j] == s[i])\)
则 \(dp[i] = \sum_{k = max (1, p - 1)}^{i - 2}{dp[k]}\)
证明:
不重:
反证法:假设会与 \(s1\) 重复
1.若 \(k \in [p + 1, i - 2]\)
\(\because k \in [p - 1, i - 2],k \neq p\)
\(\therefore s[k] \neq s[i]\)
与 \(s1\) 重复,则 \(s1\) 最后一位一定为 \(s[i]\)
矛盾
2.若 \(k = p\)
\(dp[i]\) 表示的序列为 \(dp[p]\) 包含的所有序列后加一个 \(s[i]\)。
则 \(s1\) 后加一个 \(s[i]\) 与 \(dp[p]\) 包含的某序列\((s2)\)重复,且 \(str\) 是被 \(dp[p]\) 包含的一个序列。
那么,\(s2\) 的末尾有 \(2\) 个以上的 \(s[i]\),那么 \(p\) 之前的某个位置\((idx)\) 存在一个 \(s[i]\)。
则 \(str\) 与 \(dp[idx]\) 包含的序列重复(\(idx\) 之前(不含)的一样,\(str\) 选择了 \(s[i]\),与之重复的序列选择了 \(s[idx]\))
矛盾
3.若 \(k = p - 1\)
①若 \(s[p - 1] = s[i]\),和 \(2.\) 的分析方法一样,得出:矛盾。
②若 \(s[p - 1] \neq s[i]\),\(s1\) 的末尾不为 \(s[i]\),矛盾。
综上:矛盾
综综上:矛盾,所以不重
不漏:
\(dp[k](~k\in [1, p - 1)~)\) 包含的子序列一定会与 \(dp[k](~k\in[p-1,i - 1)~)\)包含的子序列重复,和不重的 \(2.\) 分析方法一样
初始化:
\(dp[1] = 1\)
时间复杂度
对于每种字符,最多跑完整个序列,所以时间复杂度均摊下来 \(O (26n)\)
状态转移写得很清楚,代码比较简单,注意分类就行了。
(为了代码简洁,我将 \(dp[0]\) 置为 \(1\),实现与状态转移的分类略有不同)
#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define PII pair <int, int>
#define LL long long
#define ULL unsigned long long
template <typename T> void read (T &x) { x = 0; T f = 1;char tem = getchar ();while (tem < '0' || tem > '9') {if (tem == '-') f = -1;tem = getchar ();}while (tem >= '0' && tem <= '9') {x = (x << 1) + (x << 3) + tem - '0';tem = getchar ();}x *= f; return; }
template <typename T> void write (T x) { if (x < 0) {x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0'); }
template <typename T> void print (T x, char ch) { write (x); putchar (ch); }
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }
const int Maxn = 2 * 1e5;
const LL Mod = 1e9 + 7;
char s[Maxn + 5];
int len; LL dp[Maxn + 5];
int main () {
scanf ("%s", s + 1);
len = strlen (s + 1);
LL res = 1;
dp[1] = 1; dp[0] = 1;
for (int i = 2; i <= len; i++) {
for (int j = i - 1; j >= 1; j--) {
if (s[i] == s[j] && j - 1 == 0) break;
dp[i] = (dp[i] + dp[j - 1]) % Mod;
if (s[i] == s[j]) break;
}
res = (res + dp[i]) % Mod;
}
printf ("%lld", res);
return 0;
}