分段类型的dp,只不过求一个段的值略微麻烦
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
#include<string.h>
using namespace std;
const int MAXN=20010;
#define ll long long
ll dp[MAXN][2];
ll a[MAXN];
ll as[MAXN];
ll aa[MAXN];
ll ai[MAXN];
ll map[30];
int q[MAXN];//队列
char ts[30];
char s[MAXN];
int head,tail,n,m;
ll getDP(int i,int lt,int k)
{
return dp[k][lt]+ai[i]-ai[k]-(k+1)*(as[i]-as[k])-(aa[i]-aa[k]);
}
ll getUP(int k1,int k2,int lt)//k1>k2
{
return (dp[k1][lt]-ai[k1]+(k1+1)*as[k1]+aa[k1])-(dp[k2][lt]-ai[k2]+(k2+1)*as[k2]+aa[k2]);
}
ll getDOWN(int k1,int k2)//k1>k2
{
return k1-k2;
}
int main()
{
int T,R=0;
scanf("%d",&T);
while(T--)
{
R++;
int i,j;
int nt,lt;
scanf("%s",ts);
for(i=0;ts[i];i++)
map[ts[i]-'a']=i;
scanf("%d",&m);
scanf("%s",s);
n=strlen(s);
a[0]=map[s[0]-'a'];
as[0]=a[0];
aa[0]=a[0]*a[0];
ai[0]=0;
for(i=1;i<n;i++)
{
a[i]=map[s[i]-'a'];
aa[i]=aa[i-1]+a[i]*a[i];
ai[i]=ai[i-1]+i*a[i];
as[i]=as[i-1]+a[i];
}
for(i=0;i<n;i++)
dp[i][1]=ai[i]-aa[i];
for(j=2;j<=m;j++)
{
nt=j%2;
lt=(j+1)%2;
dp[j-1][nt]=-aa[j-1];
head=tail=0;
q[tail++]=j-2;
q[tail++]=j-1;
for(i=j;i<n;i++)
{
while(head+1<tail && getUP(q[head+1],q[head],lt)<=as[i]*getDOWN(q[head+1],q[head]))
head++;
dp[i][nt]=getDP(i,lt,q[head]);
while(head+1<tail && getUP(i,q[tail-1],lt)*getDOWN(q[tail-1],q[tail-2])<=getUP(q[tail-1],q[tail-2],lt)*getDOWN(i,q[tail-1]))
tail--;
q[tail++]=i;
}
}
printf("Case %d: %lld\n",R,dp[n-1][nt]);
}
return 0;
}