• bzoj 1212 [HNOI2004] L语言(不用AC自动机)


    网上的题解大多树都要建一棵trie树,并在上面跑AC自动机,然而这里有一种同样需要trie树,但时间复杂度较低的方法。

    首先,我们可以轻松列出状态转移方程 F[x]=∑| F[x-len(i)]&(is(i->x,s[i]);

    这样的复杂度是O(m*lens*∑len[i]*n),可能会超时,再加上hash之类的就可以过了,但这显然不优美。

    ====================分割线====================

    对于每个F(i),我们都是从之前的额某个F(j)转移过来的,它是true当且仅当(j+1->i)是一个单词,且f[j]是true,那么我们将每个单词反过来建一棵trie树,例如有单词abc,我们将cba插入trie树,从i开始i先匹配到每个单词的最后一位,然后再匹配到最后一位相同的倒数第二位,如此下去,当我们匹配到一个单词的开头时,并且此时的F[i-depth]为true的话,F(i)就为true了,因为每个字符在trie树上的路径唯一,且trie树的深度不超过单词的最长长度(10),所以它的复杂度还是非常可看的,复杂度为O(m*lens*dep(trie))=O(m*lens*max(strlen(word))),20*1M*10,轻松过。

    这题不难,但是如果反过来想,可以避免很多高端算法,从后往前的思想确实不错。贴一个代码,有些冗长。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<string>
     5 using namespace std;
     6 int ch[10005][20];
     7 int cnt;
     8 int n,m;
     9 char s[2000005];
    10 int col[2000005];
    11 bool dp[1000005];
    12 void insert()
    13 {
    14     int now=0;
    15     for(int i=strlen(s)-1;i>=0;i--)
    16     {
    17         int c=s[i]-'0';
    18         if(!ch[now][c])
    19         {
    20             cnt++;
    21             ch[now][c]=cnt;
    22         }
    23         now=ch[now][c];
    24     }
    25     col[now]=true;
    26 }
    27 bool cal(int x)
    28 {
    29     int deep=0;
    30     int now=0;
    31     for(int i=x;i>=1;i--)
    32     {
    33         int c=s[i]-'0';
    34         if(ch[now][c]==0)return false;
    35         now=ch[now][c];
    36         deep++;
    37         if(dp[x-deep] && col[now])return true;
    38     }
    39     return true;
    40 }
    41 void solve()
    42 {
    43     int ll=strlen(s+1);
    44     for(int i=1;i<=ll;i++)
    45     {
    46         dp[i]=cal(i);
    47     }
    48     for(int i=ll;i>=0;i--)
    49     {
    50         if(dp[i])
    51         {
    52             printf("%d
    ",i);
    53             return;
    54         }
    55     }
    56     return ;
    57 }
    58 int main()
    59 {
    60     scanf("%d%d",&n,&m);
    61     for(int i=1;i<=n;i++)
    62     {
    63         scanf("%s",s);
    64         insert();
    65     }
    66     for(int i=1;i<=m;i++)
    67     {
    68         memset(dp,0,sizeof(dp));
    69         dp[0]=true;
    70         scanf("%s",s+1);
    71         solve();
    72     }
    73     return 0;
    74 }
    View Code
  • 相关阅读:
    C语言memmove()函数:复制内存内容(可以处理重叠的内存块)
    boot简介
    MT6753/MT6755 呼吸灯功能添加
    MT6753 使用nt35596s 由于液晶极化出现的闪屏问题解决思路
    MTK平台释疑android M 配置中断相关问题
    MT6755 平台手机皮套驱动实现
    MTK平台 GPU 相关知识
    MTK平台如何定位显示花屏和界面错乱等绘制异常的问题?
    【Python】注释
    【Linux】.gz文件 压缩与解压缩命令
  • 原文地址:https://www.cnblogs.com/sillygirl/p/4641075.html
Copyright © 2020-2023  润新知