1.前言
一次失败的比赛。首先为了赶时间(其实也就争取了10min左右),我尝试在出租车上打代码,下来差点吐了 qwqqwqqwq,然后车上因为晕乎乎的,把 DDD 和 FFF 的题意读错了,把 DDD 取 maxmaxmax 读成了求和(然后还嘲讽出题人只会出换根 dpdpdp 板题,并大骂出题人不会出样例,浪费了 20min20min20min 左右),FFF 把不能留下连续的读成了不能删去连续的(然后就放弃 FFF, 撞死在 EEE 题贪心上)。总之虽然外因很多,但主要原因还是自己太菜了呀~。 不久前已经开始记录自己认为的好题,时不时重做一下吧 (虽然可能会咕)
2.题解
悲伤的回味已经过去了,现在开始进入快乐的题解部分
容易想到 dpdpdp。
状态定义:
dp[i]dp[i]dp[i]: 前 iii 个字符中选,必选第 iii 个字符,不与 s1⊆s[1,i)s1\subseteq s_{[1,i)}s1⊆s[1,i) 重复的满足要求的子序列个数。
状态转移:
1. ∀j∈[1,i),s[j]≠s[i]\forall j \in [1,i),s[j] \neq s[i]∀j∈[1,i),s[j]=s[i]
dp[i]=(∑k=1i−2dp[k])+1dp[i] = (\sum_{k = 1}^{i - 2}dp[k]) + 1dp[i]=(∑k=1i−2dp[k])+1
2. ∃j∈[1,i),s[j]=s[i]\exists j \in [1, i), s[j] = s[i]∃j∈[1,i),s[j]=s[i]
令 p=maxj(j∈[1,i),s[j]==s[i])p = \max j (j \in [1, i), s[j] == s[i])p=maxj(j∈[1,i),s[j]==s[i])
则 dp[i]=∑k=max(1,p−1)i−2dp[k]dp[i] = \sum_{k = max (1, p - 1)}^{i - 2}{dp[k]}dp[i]=∑k=max(1,p−1)i−2dp[k]
证明:
不重:
反证法:假设会与 s1s1s1 重复
1.若 k∈[p+1,i−2]k \in [p + 1, i - 2]k∈[p+1,i−2]
∵k∈[p−1,i−2],k≠p\because k \in [p - 1, i - 2],k \neq p∵k∈[p−1,i−2],k=p
∴s[k]≠s[i]\therefore s[k] \neq s[i]∴s[k]=s[i]
与 s1s1s1 重复,则 s1s1s1 最后一位一定为 s[i]s[i]s[i]
矛盾
2.若 k=pk = pk=p
dp[i]dp[i]dp[i] 表示的序列为 dp[p]dp[p]dp[p] 包含的所有序列后加一个 s[i]s[i]s[i]。
则 s1s1s1 后加一个 s[i]s[i]s[i] 与 dp[p]dp[p]dp[p] 包含的某序列(s2)(s2)(s2)重复,且 strstrstr 是被 dp[p]dp[p]dp[p] 包含的一个序列。
那么,s2s2s2 的末尾有 222 个以上的 s[i]s[i]s[i],那么 ppp 之前的某个位置(idx)(idx)(idx) 存在一个 s[i]s[i]s[i]。
则 strstrstr 与 dp[idx]dp[idx]dp[idx] 包含的序列重复(idxidxidx 之前(不含)的一样,strstrstr 选择了 s[i]s[i]s[i],与之重复的序列选择了 s[idx]s[idx]s[idx])
矛盾
3.若 k=p−1k = p - 1k=p−1
①若 s[p−1]=s[i]s[p - 1] = s[i]s[p−1]=s[i],和 2.2.2. 的分析方法一样,得出:矛盾。
②若 s[p−1]≠s[i]s[p - 1] \neq s[i]s[p−1]=s[i],s1s1s1 的末尾不为 s[i]s[i]s[i],矛盾。
综上:矛盾
综综上:矛盾,所以不重
不漏:
dp[k]( k∈[1,p−1) )dp[k](~k\in [1, p - 1)~)dp[k]( k∈[1,p−1) ) 包含的子序列一定会与 dp[k]( k∈[p−1,i−1) )dp[k](~k\in[p-1,i - 1)~)dp[k]( k∈[p−1,i−1) )包含的子序列重复,和不重的 2.2.2. 分析方法一样
初始化:
dp[1]=1dp[1] = 1dp[1]=1
时间复杂度
对于每种字符,最多跑完整个序列,所以时间复杂度均摊下来 O(26n)O (26n)O(26n)
状态转移写得很清楚,代码比较简单,注意分类就行了。
(为了代码简洁,我将 dp[0]dp[0]dp[0] 置为 111,实现与状态转移的分类略有不同)
#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;
}