zoukankan      html  css  js  c++  java
  • hdu多校第一场 1006 (hdu6583)Typewriter dp/后缀自动机

    题意:

    有个打字机,在当前字符串后新加一个字花费p,把当前字符串的一个连续子串拷贝到当前字符串的末尾花费q,给定一个字符串,求用打字机打出这个字符串的最小花费。

    题解:

    容易想到用dp

    记dp[i]为打出前i个字符的最小花费,对于每个i,令

    A=dp[i-1]+p 

    B=dp[j]+q 其中j为最小的,使得s[j+1~i]是s[1~j]的连续子串的值

    其实就是,把这个字符串咔嚓切一刀,看后面的部分是不是前面部分的子串,如果不是,就把切的地方向后挪,前面的部分是原串,后面的部分是模式串。

    dp[i]=min(A,B)

    假如在i=k的时候已经找到了这么一个最优切分点j,那么在讨论i=k+1的时候,这个最优切分点要么就是原来的j,要么就需要把这个j向后挪。

    为啥,因为j已经是令原串最短的切分点了,现在你还要往模式串后面加东西,原串不可能更短,只能更长。

    注意,在j向后移动的过程中,出现了将模式串的第一位砍掉的操作,那么问题来了,有没有一种数据结构,支持这种将模式串的前面砍掉的操作呢?

    后缀自动机。后缀自动机上一个节点代表多个连续子串,其中一个最长,剩下的都是这个最长的连续子串的后缀,父节点又是子节点的后缀,那么,对于某个自动机上的连续子串,把它最前面一位砍掉,要么它还停留在原来的节点上,要么它转移到了父节点上。

    后缀自动机增量构造复杂度O(1),状态转移复杂度O(1)

    总时间复杂度O(n)

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define maxn=200005;
    #define kind=26;
    struct state
    {
        state *Next[kind],*link;
        int len;
        state()
        {
            link=0;
            len=0;
            memset(Next,0,sizeof(Next));
        }
    };
    int sz;
    state st[maxn*2+5];
    inline state* newnode(int len = 0)
    {
        memset(st[sz].Next,0,sizeof(st[sz].Next));
        st[sz].link=0;
        st[sz].len=len;
        return &st[sz++];
    }
    state *root,*last;
    void extend(int w)
    {
        state* p=last;
        state* cur=newnode(p->len+1);
        while(p&&p->Next[w]==0)
        {
            p->Next[w]=cur;
            p=p->link;
        }
        if(p)
        {
            state* q=p->Next[w];
            if(p->len+1==q->len)
                cur->link=q;
            else
            {
                state* clone=newnode(p->len+1);
                memcpy(clone->Next,q->Next,sizeof(q->Next));
                clone->link=q->link;
                q->link=clone;
                cur->link=clone;
                while(p&&p->Next[w]==q)
                {
                    p->Next[w]=clone;
                    p=p->link;
                }
            }
        }
        else cur->link=root;
        last=cur;
    }
    
    #define ll long long
    char s[maxn];
    ll dp[maxn];
    int main()
    {
        while(~scanf("%s",s+1))
        {
            sz=0;
            root=newnode();
            last=root;
            ll p,q;
            scanf("%lld%lld",&p,&q);
            int n=strlen(s+1);
            int j=1;
            dp[1]=p;
            extend(s[1]-'a');
            state* cur=root->Next[s[1]-'a'];
            for(int i=2;i<=n;i++)
            {
                dp[i]=dp[i-1]+p;
                while(1)
                {
                    while(cur!=root && cur->link->len>=i-j-1) cur=cur->link;
                    if(cur->Next[s[i]-'a']!=NULL)
                    {
                        cur=cur->Next[s[i]-'a'];
                        break;
                    }
                    else
                        extend(s[++j]-'a');
                }
                //cout<<i<<' '<<j<<endl;
                dp[i]=min(dp[i],dp[j]+q);
            }
            printf("%lld
    ",dp[n]);
        }
    }

    PS:本人从来没搞明白subset,substring,section,子串,子序列,区间的区别,因此一般习惯称其为“连续子串/序列”,“非连续子串/子序列”

  • 相关阅读:
    摘录的WinForm Control 开发3,crystalbutton
    摘录的WinForm Control 开发2,CustomColorCheckBox,CustomColorRadioButton
    摘录的WinForm Control 开发4,控件总结
    linq to sql 简单小结:
    摘录的WinForm Control 开发5,WinForm 开发:FlashGetFormDemos ,类似FlashGet的悬浮窗
    SerialPort 的使用
    摘录的WinForm Control 开发5,WinForm 开发:MultipLanguageDemos ,多国语言开发
    摘录的WinForm Control 开发5,WinForm 开发:UnRegularFormDemos ,不规则窗体
    摘录的WinForm control 开发1..BorderLabel
    jquery上传插件(uploadify)的使用
  • 原文地址:https://www.cnblogs.com/isakovsky/p/11246450.html
Copyright © 2011-2022 走看看