Dp /单调性/SAM /更新节点(这个好坑啊)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 100010
#define INF 1000000000000000000LL
char S[N];
int c[N],Case,hehe;
long long A,B,Dp[N];
int head,tail;
struct Node{
long long value;
int pos;
}q[N];
struct SAM{
SAM *fa,*son[26];
int size,val;
void S_clear(){
fa=0;val=0;size=0;
memset(son,0,sizeof(son));
}
}*last,*tot,*root,State[N*2],*pos[N*2],*now;
void Init()
{
tot=State;now=root=last=tot++;
root->S_clear();
}
void Insert(int w)
{
SAM *p=last,*np=tot++;np->S_clear();
np->val=p->val+1;
while(p&&!p->son[w])
p->son[w]=np,p=p->fa;
if(!p)
np->fa=root;
else
{
SAM *q=p->son[w];
if(q->val==p->val+1)
np->fa=q;
else
{
SAM *nq=tot++;nq->S_clear();
nq->val=p->val+1;
memcpy(nq->son,q->son,sizeof(q->son));
nq->fa=q->fa;q->fa=np->fa=nq;
if(now==q)
now=nq;
while(p&&p->son[w]==q)
p->son[w]=nq,p=p->fa;
}
}
last=np;
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
head=0;tail=0;
scanf("%s",S+1);
for(int i=0;i<26;i++)
scanf("%d",&c[i]);
scanf("%lld%lld",&A,&B);
Init();
int len=(int)strlen(S+1);
Dp[0]=0;
int l=0;
for(int i=1,j=0;i<=len;i++)
{
int num=S[i]-'a';
Dp[i]=Dp[i-1]+c[num];
while(j+1<i&&!now->son[num])
{
Insert(S[++j]-'a');
if(now!=root&&--l==now->fa->val)
now=now->fa;
}
if(now->son[num])
now=now->son[num],l++;
else
{
Insert(S[++j]-'a');
now=root;head=tail=0;
}
while(head!=tail&&j>q[head].pos)
++head;
if(head!=tail)
Dp[i]=min(Dp[i],q[head].value+A*i+B*2);
q[tail++]=(Node){Dp[i]-A*i,i};
while(head+1!=tail&&q[tail-1].value<=q[tail-2].value)
{
tail--;
q[tail-1]=q[tail];
}
}
printf("Case #%d: %lld\n",++Case,Dp[len]);
}
return 0;
}