【JSOI2017】奥术 (递推)

https://gmoj.net/senior/#main/show/100018

很巧妙的递推题。

\(cnt[i]\)表示后缀\(i\)有多个前缀可以变成空。

若能求出最小的\(j\),满足\(s[i..j]\)会变成空,那么\(cnt[i]=cnt[j]+1\)

同理,可以设出状态\(f[i][c]\)表示要\(s[i..f[i][c]-1]\)变成\(c\)\(f[i][c]\)最小是多少。

倒着枚举\(i\)\(f\)有初值\(f[i][s[i]]=i+1\)

然后从小到大枚举字符\(c\),假设已经求出了\(f[i][c]\)

若有一条限制\((x,y,z)\)\(x=c\),那么就有一种走法\(f[i][z]=f[f[i][x]][y]\)

取所有走法的\(f[f[i][x]][y]\)的最小值,那么这就是下一步走到的地方。

注意还有一种转移是\(f[i][c]=f[f[i][*]][c]\)

所以先做一次求出\(f[i][*]\),再做一次用\(f[i][*]\)去更新\(f[i][c]\)

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int N = 2e5 + 5;

char s[N], str[10];

int n, len, a[N][3];

const int inf = 1e9;

int f[N][27];

ll cnt[N];

int main() {
	freopen("arcane.in", "r", stdin);
	freopen("arcane.out", "w", stdout);
	scanf("%s", s + 1);
	len = strlen(s + 1);
	scanf("%d", &n);
	fo(i, 1, n) {
		fo(j, 0, 2) {
			scanf("%s", str);
			a[i][j] = str[0] == '*' ? 26 : str[0] - 'a';
		}
	}
	fo(i, 1, len + 1) {
		fo(j, 0, 26) f[i][j] = inf;
	}
	fd(i, len, 1) {
		f[i][s[i] - 'a'] = i + 1;
		fo(j, 0, 25) {
			if(f[i][26] < inf)
				f[i][j] = min(f[i][j], f[f[i][26]][j]);
			if(f[i][j] < inf) {
				int mi = len + 1;
				fo(k, 1, n) if(a[k][0] == j)
					mi = min(mi, f[f[i][j]][a[k][1]]);
				fo(k, 1, n) if(a[k][0] == j && mi == f[f[i][j]][a[k][1]])
					f[i][a[k][2]] = min(f[i][a[k][2]], mi);
			}
		}
		fo(j, 0, 25) {
			if(f[i][26] < inf)
				f[i][j] = min(f[i][j], f[f[i][26]][j]);
			if(f[i][j] < inf) {
				int mi = len + 1;
				fo(k, 1, n) if(a[k][0] == j)
					mi = min(mi, f[f[i][j]][a[k][1]]);
				fo(k, 1, n) if(a[k][0] == j && mi == f[f[i][j]][a[k][1]])
					f[i][a[k][2]] = min(f[i][a[k][2]], mi);
			}
		}
		if(f[i][26] < inf) cnt[i] = cnt[f[i][26]] + 1;
	}
	ll ans = 0;
	fo(i, 1, len) ans += cnt[i];
	pp("%lld\n", ans);
}
posted @ 2020-04-21 16:25  Cold_Chair  阅读(221)  评论(0编辑  收藏  举报