【题目大意】
有一个长度为n(1<=n<=10^5),均由小写字母组成的字符串st,且最大的字母不超过M(1<=M<=26,将字母用数字表示,a为1).有M*M的矩阵a,a[i][j]表示将i修改j要花费a[i][j]的费用。求将字符串st修改成字符串s,字符串s满足s[i]=s[j],s[i-1]≠s[i]且s[j]≠s[j+1],j-i+1>=k。
【解题思路】
先用floyd算法处理a[i][j],保证a[i][j]是最小的。
g[i][j]表示将st前i个字符全变成j的费用。
(字符串的第一位下标为1)
f[i][j]表示长度为i,第i位为j且满足题意的最小花费。
第i为可以接着上一段,也可以重新开一段(i-k+1 ~ i)
f[i][j]=min(f[i-1][j],min(f[i][k])+g[i][j]-g[i-k][j]) ,1<=k<=M
【代码】
#include <cstdio>
#include <string>
#include <iostream>
using namespace std;
string st;
long long a[30][30];
long long f[101010][30];
long long g[101010][30];
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
cin>>st;
st='X'+st;
for (int i=1;i<=m;i++)
for (int j=1;j<=m;j++)
scanf("%lld",&a[i][j]);
for (int k=1;k<=m;k++)
for (int i=1;i<=m;i++)
for (int j=1;j<=m;j++)
if (a[i][j]>a[i][k]+a[k][j]) a[i][j]=a[i][k]+a[k][j];
for (int i=1;i<=m;i++)
for (int j=1;j<st.size();j++)
g[j][i]=g[j-1][i]+a[st[j]-'a'+1][i];
for (int i=1;i<=m;i++)
f[k][i]=g[k][i];
for (int i=k+1;i<st.size();i++)
{
long long mn=9999999999999;
if (i-k<k)
{
for (int s=1;s<=m;s++)
f[i][s]=g[i][s];
}else
{
for (int s=1;s<=m;s++)
if (f[i-k][s]<mn) mn=f[i-k][s];
for (int s=1;s<=m;s++)
f[i][s]=mn+g[i][s]-g[i-k][s];
for (int s=1;s<=m;s++)
if (f[i-1][s]+a[st[i]-'a'+1][s]<f[i][s])
f[i][s]=f[i-1][s]+a[st[i]-'a'+1][s];
}
}
long long ans=9999999999999;
for (int i=1;i<=m;i++)
if (ans>f[st.size()-1][i]) ans=f[st.size()-1][i];
printf("%lld\n",ans);
}