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\n",sam.getdp());
}
return 0;
}
/***
hdfajklshghghfklashfghghghghgasldifffddsuhsdfgahsufgajsdkhfasdfhdfasgdfsghghdhfjkasdfhasdfhsadghghlkfhaskdfhadfgalghghdfjhasghghghkdjfhaksf
2 1
out:87
***/