[bzoj4713]迷失的字符串【bitset】【树形dp】

【题目链接】
  https://www.lydsy.com/JudgeOnline/problem.php?id=4713
【题解】
  首先考虑只有一个串时的做法,可以进行dp,记 f i , j 表示从 i 的子树中任意一点出发到 i 能否匹配字符串的 1.. j 位且 i j 匹配。同时记 g i , j 表示从 i 的子树中出发到 i 能否从后往前匹配字符串的 j . . l e n 位并且 i j 匹配。
  显然有 f i , j = f i , j | ( f k , j 1 & [ c h == s j ] ) f i , 0 = t r u e
   g i , j = g i , j | ( g k , j + 1 & [ c h == s j ] ) f i , l e n + 1 = t r u e
   ( k i , c h )
  那么我们在lca处统计答案。如果存在 f i , j == t r u e g i , j + 1 == t r u e 那么就可以在以 i 为子树的字符树中匹配。
  接下来我们把所有的询问串拼在一起,然后一起执行dp,并且通过bitset优化位运算的转移。就可以在合理的复杂度解决该题。
  但是bzoj太慢了,所以可以把长度为1的询问串特判掉来优化常数。
  时间复杂度 O ( N ( l e n + M ) / 64 )
【代码】

/* - - - - - - - - - - - - - - -
    User :      VanishD
    problem :   [bzoj3713]
    Points :    bitset
- - - - - - - - - - - - - - - */
# include <bits/stdc++.h>
# define    ll      long long
# define    inf     0x3f3f3f3f
# define    N       30010
# define    M       35010
using namespace std;
int read(){
    int tmp = 0, fh = 1; char ch = getchar();
    while (ch < '0' || ch > '9'){ if (ch == '-') fh = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9'){ tmp = tmp * 10 + ch - '0'; ch = getchar(); }
    return tmp * fh;
}
struct Edge{
    int data, next, vote;
}e[N * 2];
int head[N], place, n, m, sum, s[N], t[N], ch[M], belong[M], final[N], q[N], pl, pr, use[N], wi[200]; 
char st[N];
bitset <M> f[N], g[N], pre, bak, hav[27], ans, nowpre, nowbak;
void build(int u, int v, int c){
    e[++place].data = v; e[place].next = head[u]; head[u] = place; e[place].vote = c;
}
void dfs(int x, int fa){
    for (int ed = head[x]; ed != 0; ed = e[ed].next)
        if (e[ed].data != fa)
            dfs(e[ed].data, x);
    q[++pr] = x;
}
void bfs(){
    pl = 1, pr = n; 
    while (pl <= pr){
        int x = q[pl++]; use[x] = true;
        f[x] = pre; g[x] = bak;
        for (int ed = head[x]; ed != 0; ed = e[ed].next)
            if (use[e[ed].data] == true){
                nowpre = (f[e[ed].data] << 1) & hav[e[ed].vote];
                nowbak = (g[e[ed].data] >> 1) & hav[e[ed].vote];
                ans = ans | (f[x] & (nowbak >> 1)) | (nowpre & (g[x] >> 1));
                f[x] = f[x] | nowpre; g[x] = g[x] | nowbak;
        }
    } 
}
int main(){
//  freopen("bzoj4713.in", "r", stdin);
//  freopen("bzoj4713.out", "w", stdout);
    n = read();
    for (int i = 1; i < n; i++){
        int u = read(), v = read();
        char c;
        scanf("\n%c", &c); c -= 'a' - 1;
        build(u, v, c); build(v, u, c);
        wi[c] = true;
    }
    m = read();
    sum = 0;
    for (int i = 1; i <= m; i++){
        s[i] = sum;
        scanf("\n%s", st + 1);  
        int l = strlen(st + 1); 
        if (l == 1){
            if (wi[st[1] - 'a' + 1] == true)
                final[i] = true;
            continue;
        }
        for (int j = 1; j <= l; j++)
            ch[sum + j] = st[j] - 'a' + 1;
        t[i] = sum + l + 1;
        for (int j = s[i]; j < t[i]; j++) belong[j] = i;
        sum = sum + l + 1;
    }
    for (int i = 1; i <= m; i++) pre.set(s[i]);
    for (int i = 1; i <= m; i++) bak.set(t[i]);
    for (int i = 1; i <= 26; i++)
        for (int j = 0; j <= sum; j++)
            if (ch[j] == i) hav[i].set(j);
    pl = 1, pr = 0; dfs(1, 0);
    bfs();
    for (int i = 0; i <= sum; i++)
        if (ans[i] == 1) final[belong[i]] = true;
    for (int i = 1; i <= m; i++)
        if (final[i] == true)
            puts("YES"); else puts("NO");   
    return 0;
}

猜你喜欢

转载自blog.csdn.net/d_vanisher/article/details/80787232
今日推荐