[HNOI2004]L语言 (Trie树+dp)

[HNOI2004]L语言 解题报告
这似乎是一道各种字符串算法的模板题,例如Trie树,AC自动机,甚至还有用KMP的,666
数据很水放了几个暴力的过了
dp当然也是很好想的
dp[i]表示字符串前i段是否能够被匹配
我们枚举一个k∈(0,j),如果前k段能够匹配到,那么我们只用考虑k+1到j这一段是否能够在字典里头查找到,
于是顺理成章想到字典树(基本操作不讲了)
转移方程:dp[i]|=dp[k]&find(k+1,i),即如果一个k可行,那么dp[i]就位true
那么问题就搞定啦

代码:

#include <bits/stdc++.h>
using namespace std ;

#define rep(i, a, b) for (int (i) = (a); (i) <= (b); (i)++)
#define Rep(i, a, b) for (int (i) = (a) - 1; (i) < (b); (i)++)
#define REP(i, a, b) for (int (i) = (a); (i) >= (b); (i)--)
#define clr(a) memset(a, 0, sizeof(a))
#define Sort(a, len, cmp) sort(a + 1, a + len + 1, cmp)
#define ass(a, sum) memset(a, sum, sizeof(a))

#define ls ((rt) << 1)
#define rs ((rt) << 1 | 1)
#define lowbit(x) (x & -x)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define endl '\n'
#define ENDL cout << endl
#define SZ(x) ((int)x.size())

typedef long long ll ;
typedef unsigned long long ull ;
typedef vector <int> vi ;const int N = 2000010 ;
const int M = 210 ;
const double eps = 1e-8 ;
const int iinf = INT_MAX ;
const ll linf = 2e18 ;
const double dinf = 1e30 ;
const int MOD = 1000000007 ;

inline int read(){
    int X = 0, w = 0 ;
    char ch = 0 ;
    while (!isdigit(ch)) { w |= ch == '-' ; ch = getchar() ; }
    while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar() ;
    return w ? - X : X ;
}

void write(int x){
     if (x < 0) putchar('-'), x = - x ;
     if (x > 9) write(x / 10) ;
     putchar(x % 10 + '0') ;
}

void print(int x) {
    cout << x << endl ;
    exit(0) ;
}

void PRINT(string x) {
    cout << x << endl ;
    exit(0) ;
}

void douout(double x){
     printf("%lf\n", x + 0.0000000001) ;
}
int n, m, ans, len, id ;
string s, str ;
int dp[N], trie[M][26], val[M] ;

void insert(string s) {
    len = max(len, SZ(s)) ;
    int now = 0 ;
    for (int i = 0; i < SZ(s); i++) {
        int c = s[i] - 'a' ;
        if (!trie[now][c]) trie[now][c] = ++id ;
        now = trie[now][c] ;
    }
    val[now] = 1 ;
}

bool find(int s, int t) {
    int now = 0 ;
    for (int i = s; i <= t; i++) {
        int c = str[i] - 'a' ;
        if (!trie[now][c]) return 0 ;
        now = trie[now][c] ;
    }
    return val[now] ;
}

signed main(){
    scanf("%d%d", &n, &m) ;
    for (int i = 1; i <= n; i++) {
        cin >> s ;
        insert(s) ;
    }
    for (int i = 1; i <= m; i++) {
        cin >> str ;
        clr(dp) ; ans = 0 ;
        for (int j = 0; j < SZ(str); j++)
        for (int k = max(j - len, -1); k <= j; k++)
        if ((k == -1 || dp[k]) && find(k + 1, j)) {
            dp[j] = 1 ;
            ans = j + 1 ;
            break ;
        }
        printf("%d\n", ans) ;
    }
}

 

posted @ 2018-12-03 22:08  harryhqg  阅读(265)  评论(0编辑  收藏  举报