HDU 6583 Typewriter(后缀自动机)
\(f[i]\)表示到\(i\)所需最小花费
假设\(j\)是满足\(s[j,i]\)是\(s[1,j-1]\)的子串的最小值,则\(f[i] = min(f[i−1]+p,f[j−1]+q)\) \((\)因为\(f[i]\)是非递减的\()\)
#include <bits/stdc++.h>
#define Cpy(a, b) memcpy(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int maxn = 200010;
const int Maxn = 400010;
char s[maxn];
struct Suffix_Automata
{
int maxlen[Maxn], trans[Maxn][26], link[Maxn], Size, Last;
int now; //now表示前一次匹配的状态 即在s[1,j-1]中包含子串s[j,i-1]的状态
void init()
{
now=1;
Size = Last = 1;
link[1] = 0;
memset(trans[1], 0, sizeof(trans[1]));
}
int newnode()
{
int node = (++Size);
link[node] = 0;
memset(trans[node], 0, sizeof(trans[node]));
return node;
}
void Extend(int id)
{
int cur = newnode(), p;
maxlen[cur] = maxlen[Last] + 1;
for (p = Last; p && !trans[p][id]; p = link[p])
trans[p][id] = cur;
if (!p)
link[cur] = 1;
else
{
int q = trans[p][id];
if (maxlen[q] == maxlen[p] + 1)
link[cur] = q;
else
{
int clone = newnode();
maxlen[clone] = maxlen[p] + 1;
Cpy(trans[clone], trans[q]);
link[clone] = link[q];
for (; p && trans[p][id] == q; p = link[p])
trans[p][id] = clone;
link[cur] = link[q] = clone;
}
}
Last = cur;
}
bool match(int id)
{
return trans[now][id]==0;
}
void withdraw(int len)
{
while(now>1 && maxlen[link[now]]>=len)
now=link[now];
}
void Transfer(int id,int len)
{
now=trans[now][id];
if(!now)now=1;
// if(len==0) //(之前的now的len) +1后一定在之后的now中,除了len=0的情况
withdraw(len);
}
} sam;
ll f[maxn];
int main()
{
int a,b;
while(~scanf("%s", s + 1))
{
sam.init();
scanf("%d%d",&a,&b);
int len = strlen(s + 1);
f[1]=a;
sam.Extend(s[1]-'a');
int j=2;
for(int i=2;i<=len;i++)
{
f[i]=f[i-1]+a;
//若上次状态没有该字符的转移 或者 当前子串(s[j,i])长于这个前缀(s[1,j-1]) 并且子串中还有字符
//说明当前j不满足条件,必须往右移
while((sam.match(s[i]-'a')||(i-j+1)>i)&&j<=i)
{
sam.Extend(s[j++]-'a');
sam.withdraw(i-j); //s[j,i-1]的长度变短,调整now的位置,这时s[i]还不包括,故长度为i-j
}
sam.Transfer(s[i]-'a',i-j+1); //确定长度和状态之后调整
if(j<=i)
f[i]=min(f[i],f[j-1]+b);
}
printf("%lld\n",f[len]);
}
return 0;
}

浙公网安备 33010602011771号