zoukankan      html  css  js  c++  java
  • UVALive

    给出一个长度不超过300000的字符串 S,然后给出 n 个长度不超过100的字符串。

    如果字符串可以多次使用,用这 n 个字符串组成 S 的方法数是多少?

     

    比如样例中,abcd = a + b + cd = ab + cd

    dp[i] 表示用这n个字符串构成,S中从 i ~ len之间的字母构成的子串,的可分解方案数。

    如果存在一个位置 x >= i, 且 i~x 之间的字母是一个单词,那么dp[i] = ∑ ( dp[x] )

    但是如果暴力枚举 i ~ x是不是一个单词,必然会TLE。这时我们就需要 Trie 树优化这个DP。

    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    using namespace std;
    #define maxn 400000 + 100
    #define sigma_size 27
    #define LL long long
    #define MOD 20071027
    
    int tot = 0;
    int trie[maxn][sigma_size], sum[maxn], dp[maxn];
    
    void insert(char s[])
    {
            int root = 0;
            for (int i = 0; s[i]; i++)
            {
                    int id = s[i]-'a';
                    if (!trie[root][id])
                    {
                            sum[++tot] = 0;
                            trie[root][id] = tot;
                    }
                    root = trie[root][id];
            }
            sum[root] = 1;
    }
    
    void found(char s[], int k)
    {
            int root = 0;
            for (int i = k; s[i]; i++)
            {
                    int id = s[i]-'a';
                    if (!trie[root][id])
                            return;
                    root = trie[root][id];
                    if (sum[root])
                            dp[k] = (dp[k]+dp[i+1])%MOD;
            }
    }
    
    int main()
    {
            char s[maxn];
            int len, ca = 0;
            while(scanf("%s", s) != EOF)
            {
                    char t[maxn];
                    int n;
                    scanf("%d", &n);
    
                    memset(trie, 0, sizeof(trie));
                    memset(sum, 0, sizeof(sum));
                    for (int i = 1; i <= n; i++)
                    {
                            scanf("%s", t);
                            insert(t);
                    }
    
                    memset(dp, 0, sizeof(dp));
    
                    len = strlen(s);
    
                    dp[len] = 1;
                    for (int i = len-1; i >= 0; i--)
                            found(s, i);
    
                    printf("Case %d: %d
    ", ++ca, dp[0]);
            }
    }
  • 相关阅读:
    ckplayer不支持谷歌92版本,flashplayer不支持m3u8的方案
    git merge 失败
    在SuperSocket中使用Unity注入
    在WPF中集成SuperSocket 2.0
    在WPF中打印A4纸
    使用 HoloLens 仿真器
    C# 优化内存和运行效率
    Redis 高可用篇:你管这叫 Sentinel 哨兵集群原理
    Redis 核心篇:唯快不破的秘密
    Redis 日志篇:无畏宕机快速恢复的杀手锏
  • 原文地址:https://www.cnblogs.com/ruthank/p/9469084.html
Copyright © 2011-2022 走看看