zoukankan      html  css  js  c++  java
  • hdu 6583 后缀自动机

    hdu 6583 后缀自动机
    题意:
    构造字符串凭空加一个花费q,复制之前的一段花费p。
    思路:
    这是个假题解,因为并没有卡进1500ms,差个100~200ms,这是真的气。
    dp方程转移就是贪心的找最长的之前出现过的后缀。根据parent树的性质,每个父亲都是儿子的后缀,只需要知道父亲第一次出现的right就好了。
    当个后缀自动机的模板,但是代码写搓了TLE,对拍了一下思路没什么问题。
    (这题还有个加强版,(复制的花费=P*复制的长度),要用单调栈来维护)

    //#pragma comment (linker,"/STACK:102400000,102400000")
    #include<cstdio>
    #include<cstring>
    //#include <bits/stdc++.h>
    using namespace std;
    #define X first
    #define Y second
    #define PB emplace_back
    //#define LL long long
    #define pii pair<int,int>
    #define MEM(x,y) memset(x,y,sizeof(x))
    #define bug(x) cout<<"debug "#x" is "<<x<<endl;
    #define FIO ios::sync_with_stdio(false);
    #define ALL(x) x.begin(),x.end()
    #define LOG 14
    const int inf =0x3f3f3f3f;
    const int maxn =4e5+7;
    char s[maxn];
    int N;
    int P,Q;
    int fa[LOG][maxn];
    int dp[maxn];
    int dis[maxn];
    struct SAM{//下标从1开始,0作为保留位,用于做哨兵
        //private:
        struct node{
            int len,par,trans[27];
            //node(int parent,int length) :par(parent),len(length){ memset(trans,-1,sizeof(trans));}
        };
        node nd[maxn];
        int sz;
        inline void newnode(int parent,int length){node &n=nd[sz];n.par=parent,n.len=length;memset(n.trans,-1,sizeof(n.trans));++sz;};
        int last;
        //public:
        //vector<node> nd;
        SAM():last(1){sz=0;newnode(0,0);newnode(0,0);}
        void init(){last=1;sz=0;newnode(0,0);newnode(0,0);}
        void extend(const char c){
            register int p=last;
            newnode(1,nd[last].len+1);//新建状态,先让parent指向根(1)
            int np=sz-1;
            while(p!=0&&nd[p].trans[c]==-1){//如果没有边,且不为空,根也是要转移的
                nd[p].trans[c]=np;//他们都没有向np转移的边,直接连过去
                p=nd[p].par;//往parent走
            }
            if(p!=0){//如果p==0,直接就结束了,什么都不用做,否则节点p是第一个拥有转移c的状态,他的祖先都有转移c
                int q=nd[p].trans[c];//q是p转移后的状态
                if(nd[q].len==nd[p].len+1)nd[np].par=q;//len[q]是以前的最长串,len[p]+1是合并后的最长串,相等的话,不会影响,直接结束了,
                else{
                    newnode(nd[q].par,nd[p].len+1);
                    const int nq=sz-1;
                    node &n=nd[nq];
                    node &m=nd[q];
                    for(register short i=25;i+1;--i) n.trans[i]=m.trans[i];
                    nd[np].par=nd[q].par=nq;//改变parent树的形态
                    while(nd[p].trans[c]==q){//一直往上面走
                        nd[p].trans[c]=nq;//所有向q连边的状态都连向nq
                        p=nd[p].par;
                    }
                }
            }
            last=np;//最后的那个节点
        }
        int getdp(){
            memset(dis,inf,sizeof(int)*sz);
            register int top=1;
            dis[1]=0;
            dp[0]=0;
            fa[0][1]=1;
            for(register int i=sz-1;i>=2;--i)fa[0][i]=nd[i].par;
            for(register short k=1;k<LOG;++k)for(register int i=sz-1;i>=1;--i)fa[k][i]=fa[k-1][fa[k-1][i]];
            for(register int i=0;i<N;++i){
                top=nd[top].trans[s[i]-'a'];
                register const int ll=nd[top].len;
                dp[i+1]=dp[i]+P;
                register int j=-1,idx=top;
                for(register short k=LOG-1;k>=0;--k)
                    if(fa[k][idx]!=1&&dis[fa[k][idx]]+nd[fa[k][idx]].len>ll)
                        idx=fa[k][idx];
                j=fa[0][idx];
                const int mx=dp[i+1-nd[j].len]+Q;
                if(j!=1&&dis[j]+nd[j].len<=ll&&dp[i+1]>mx)
                    dp[i+1]=mx;
                dis[top]=ll;
                register int x=top;
                while(dis[nd[x].par]==inf){
                    dis[nd[x].par]=ll;
                    x=nd[x].par;
                }
            }
            return dp[N];
        }
    }sam;
    int main(){
        //freopen("02", "r", stdin);
        //freopen("02.txt", "w", stdout);
        while(~scanf("%s%d%d",s,&P,&Q)){
            sam.init();
            N=strlen(s);
            for(int i=0;i<N;++i)sam.extend(s[i]-'a');
            printf("%d
    ",sam.getdp());
        }
        return 0;
    }
    
    /***
    hdfajklshghghfklashfghghghghgasldifffddsuhsdfgahsufgajsdkhfasdfhdfasgdfsghghdhfjkasdfhasdfhsadghghlkfhaskdfhadfgalghghdfjhasghghghkdjfhaksf
    2 1
    
    out:87
    ***/
    
    
  • 相关阅读:
    POJ 1113 Wall
    POJ 2159 Ancient Cipher
    POJ 3253 Fence Repair
    HDU 5444 Elven Postman
    HDU 5432 Pyramid Split
    数据库 组合查询
    数据库 简单的数据查询
    数据库 聚合函数与分组
    数据库 使用DML语句更改数据
    数据库的数据完整性
  • 原文地址:https://www.cnblogs.com/zhangxianlong/p/11634080.html
Copyright © 2011-2022 走看看