• bzoj 2121 DP


      首先如果我们能处理出来i,j段能不能消掉,这样就可以直接dp转移了,设w[i]为前i为最少剩下多少,那么w[i]=w[j-1] (flag[j][i])。

      现在我们来求flag[i][j],首先我们可以把字符串组建立trie然后处理在串L中从left位置开始的所有的flag,那么我们可以在trie上一直往下走,每到一个标记的点就将当前的flag[left][right]设为1,那么这样可以处理出连续可以消掉的字符串,然后就处理对于类似L为abcde,字符串组为ade,bc这样可以先消一个,然后再消的情况,这样我们可以发现,如果对于当前的left,right存在flag[i][right]=1,那么就是这样的情况,那么我们直接递归处理left,i就好了,但是我们发现这里的flag[i][right]的i是大于left的,所以我们在处理以某个为开头的所有的flag的时候需要倒序处理。

      有一个优化,在同一个left时,我们在处理flag的时候有两种拓展情况,所以对于每一个i我们记录一个vis[i][j],表示在当前的left,i节点,right为j的情况是否访问过,这样有访问的情况return就好了。

      反思:开始没加优化,挺快就a了,后来加了优化之后,因为我用的指针存的trie,所以vis数组中节点的编号需要对于每个指针都存一个编号,但是这个编号不知道怎么回事儿,一申请就re,后面的按照不加优化的写,只是在node那在cnt之前申请一个num就会re,在cnt之后申请就没问题,调了半个上午也不知道怎么回事儿= =,原来一直是这么写的啊。

      反思2:后来发现是return的条件为right>=len,写成right>len了,这样就有了未定义行为。

    /**************************************************************
        Problem: 2121
        User: BLADEVIL
        Language: C++
        Result: Accepted
        Time:132 ms
        Memory:158900 kb
    ****************************************************************/
     
    //By BLADEVIL
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define maxn 200
    #define maxm 1010
     
    using namespace std;
     
    struct node{
        int cnt,num; 
        node *child[30];
        node(){ 
            cnt=num=0;
            memset(child,0,sizeof child);
        }
    }nodepool[maxm],*totnode,*rot;
     
    char s[maxn];
    int flag[maxn][maxn],vis[maxn][maxm][maxn],w[maxn];
    int n,len;
     
     
    void build_trie(){
        int j=1;
        totnode=nodepool; rot=totnode++;
        scanf("%d",&n);
        char ch[maxn];
        while (n--) {
            scanf("%s",ch);
            int len=strlen(ch);
            node *t=rot;
            for (int i=0;i<len;i++) {
                if (!t->child[ch[i]-'a']) t->child[ch[i]-'a']=totnode++,t->child[ch[i]-'a']->num=j++;
                t=t->child[ch[i]-'a'];
            }
            t->cnt=1;
        }
    }
     
    void make(node *rot,int left,int right) {
        //printf("%d ",rot->num);
        if (rot->cnt) flag[left][right-1]=1;
        if (vis[left][rot->num][right]) return ;
        if (right>=len) return ;
        vis[left][rot->num][right]=1;
        if (rot->child[s[right]-'a']) make(rot->child[s[right]-'a'],left,right+1);
        for (int i=right;i<len;i++) if (flag[right][i]) make(rot,left,i+1);
    }
     
    int main() {
        scanf("%s",s); len=strlen(s);
        build_trie();
        for (int i=len-1;i>=0;i--) make(rot,i,i);
        /*for (int i=0;i<len;i++) {
            for (int j=0;j<len;j++) printf("%d ",flag[i][j]);
            printf("
    ");
        }*/
        w[0]=0;
        for (int i=0;i<len;i++) {
            w[i+1]=w[i]+1;
            for (int j=0;j<=i;j++) 
                if (flag[j][i]) w[i+1]=min(w[i+1],w[j]);
            //printf("%d ",w[i]);
        }
        //printf("
    ");
        printf("%d
    ",w[len]);
        return 0;
    }
  • 相关阅读:
    Asp.net 文件下载,中文文件名出现乱码
    存储过程中执行动态Sql语句
    SQLServer : EXEC和sp_executesql的区别
    C# 从服务器下载文件代码
    在windows 7 上为 sqlserver 2008 启用远程访问
    数字求和
    大道至简第一章读后感
    作业
    SharePoint2013 App 开发中 自定义网站栏,内容类型,列表。
    SharePoint2013 App开发模式
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3591127.html
Copyright © 2020-2023  润新知