ABC214 F 题题解 + 记一次失败的比赛

1.前言

一次失败的比赛。首先为了赶时间(其实也就争取了10min左右),我尝试在出租车上打代码,下来差点吐了 q w q qwq qwq,然后车上因为晕乎乎的,把 D D D F F F 的题意读错了,把 D D D m a x max max 读成了求和(然后还嘲讽出题人只会出换根 d p dp dp 板题,并大骂出题人不会出样例,浪费了 20 m i n 20min 20min 左右), F F F 把不能留下连续的读成了不能删去连续的(然后就放弃 F F F, 撞死在 E E E 题贪心上)。总之虽然外因很多,但主要原因还是自己太菜了呀~。 不久前已经开始记录自己认为的好题,时不时重做一下吧 (虽然可能会咕)

2.题解

悲伤的回味已经过去了,现在开始进入快乐的题解部分

容易想到 d p dp dp


状态定义:
d p [ i ] dp[i] dp[i]: 前 i i i 个字符中选,必选第 i i i 个字符,不与 s 1 ⊆ s [ 1 , i ) s1\subseteq s_{[1,i)} s1s[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]

d p [ i ] = ( ∑ k = 1 i − 2 d p [ k ] ) + 1 dp[i] = (\sum_{k = 1}^{i - 2}dp[k]) + 1 dp[i]=(k=1i2dp[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 = max ⁡ j ( 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])

d p [ i ] = ∑ k = m a x ( 1 , p − 1 ) i − 2 d p [ k ] dp[i] = \sum_{k = max (1, p - 1)}^{i - 2}{dp[k]} dp[i]=k=max(1,p1)i2dp[k]


证明:

不重:
反证法:假设会与 s 1 s1 s1 重复
1.若 k ∈ [ p + 1 , i − 2 ] k \in [p + 1, i - 2] k[p+1,i2]
∵ k ∈ [ p − 1 , i − 2 ] , k ≠ p \because k \in [p - 1, i - 2],k \neq p k[p1,i2],k=p
∴ s [ k ] ≠ s [ i ] \therefore s[k] \neq s[i] s[k]=s[i]
s 1 s1 s1 重复,则 s 1 s1 s1 最后一位一定为 s [ i ] s[i] s[i]
矛盾

2.若 k = p k = p k=p
d p [ i ] dp[i] dp[i] 表示的序列为 d p [ p ] dp[p] dp[p] 包含的所有序列后加一个 s [ i ] s[i] s[i]
s 1 s1 s1 后加一个 s [ i ] s[i] s[i] d p [ p ] dp[p] dp[p] 包含的某序列 ( s 2 ) (s2) (s2)重复,且 s t r str str 是被 d p [ p ] dp[p] dp[p] 包含的一个序列。
那么, s 2 s2 s2 的末尾有 2 2 2 个以上的 s [ i ] s[i] s[i],那么 p p p 之前的某个位置 ( i d x ) (idx) (idx) 存在一个 s [ i ] s[i] s[i]
s t r str str d p [ i d x ] dp[idx] dp[idx] 包含的序列重复( i d x idx idx 之前(不含)的一样, s t r str str 选择了 s [ i ] s[i] s[i],与之重复的序列选择了 s [ i d x ] s[idx] s[idx]
矛盾

3.若 k = p − 1 k = p - 1 k=p1
①若 s [ p − 1 ] = s [ i ] s[p - 1] = s[i] s[p1]=s[i],和 2. 2. 2. 的分析方法一样,得出:矛盾。
②若 s [ p − 1 ] ≠ s [ i ] s[p - 1] \neq s[i] s[p1]=s[i] s 1 s1 s1 的末尾不为 s [ i ] s[i] s[i],矛盾。

综上:矛盾

上:矛盾,所以不重


不漏:
d p [ k ] (   k ∈ [ 1 , p − 1 )   ) dp[k](~k\in [1, p - 1)~) dp[k]( k[1,p1) ) 包含的子序列一定会与 d p [ k ] (   k ∈ [ p − 1 , i − 1 )   ) dp[k](~k\in[p-1,i - 1)~) dp[k]( k[p1,i1) )包含的子序列重复,和不重的 2. 2. 2. 分析方法一样


初始化:
d p [ 1 ] = 1 dp[1] = 1 dp[1]=1


时间复杂度

对于每种字符,最多跑完整个序列,所以时间复杂度均摊下来 O ( 26 n ) O (26n) O(26n)


状态转移写得很清楚,代码比较简单,注意分类就行了。

(为了代码简洁,我将 d p [ 0 ] dp[0] dp[0] 置为 1 1 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;
}
posted @ 2021-08-15 19:12  C2022lihan  阅读(12)  评论(0编辑  收藏  举报