zoukankan      html  css  js  c++  java
  • 【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("
    ")
    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
    ", ans);
    }
    
  • 相关阅读:
    [湖南集训]谈笑风生
    【SCOI2010】序列操作
    ●BZOJ 3994 [SDOI2015]约数个数和
    ●BZOJ 3309 DZY Loves Math
    ●UOJ 21 缩进优化
    ●BZOJ 2693 jzptab
    ●BZOJ 2154 Crash的数字表格
    ●BZOJ 3529 [Sdoi2014]数表
    ●2301 [HAOI2011] Problem b
    ●BZOJ 2820 YY的GCD
  • 原文地址:https://www.cnblogs.com/coldchair/p/12745486.html
Copyright © 2011-2022 走看看