给一个序列 P N PN PN,该序列是 a − z a-z a−z 的排列,再给一个序列 N M = C 0 C 1 ⋯ C n − 1 ‾ NM=\overline{C_0C_1\cdots C_{n-1}} NM=C0C1⋯Cn−1,对于该序列的第 i i i 个字符 C i C_i Ci,定义 P O S i POS_i POSi 为字符 C i C_i Ci 在序列 P N PN PN 中的位置(从 0 0 0 开始),定义总体花费为:
∑ i = 0 n − 1 ( i − P O S i ) ∗ P O S i \sum_{i=0}^{n-1}(i-POS_i)*POS_i i=0∑n−1(i−POSi)∗POSi
题目给了个例子:
然后把这个序列分成
k
k
k 段,然后每段分别计算这个花费,之后再求和,问最小花费和是多少?
设 d p [ i ] [ j ] dp[i][j] dp[i][j] 为前 i i i 个分 j j j 段,则有递推方程:
d p [ i ] [ j ] = min { d p [ k ] [ j − 1 ] + ∑ m = k + 1 i ( m − k − 1 − p [ a [ m ] ] ) ∗ p [ a [ m ] ] } d p [ i ] [ j ] = min { d p [ k ] [ j − 1 ] + s [ i ] − s [ k ] − ( k + 1 ) ( s p [ i ] − s p [ k ] ) } \begin{aligned} dp[i][j]&=\min\{dp[k][j-1]+\sum_{m=k+1}^{i}(m-k-1-p[a[m]])*p[a[m]]\}\\ dp[i][j]&=\min\{dp[k][j-1]+s[i]-s[k]-(k+1)(sp[i]-sp[k])\} \end{aligned} dp[i][j]dp[i][j]=min{dp[k][j−1]+m=k+1∑i(m−k−1−p[a[m]])∗p[a[m]]}=min{dp[k][j−1]+s[i]−s[k]−(k+1)(sp[i]−sp[k])}
其中 s [ i ] = ∑ m = 0 i ( m − p [ a [ m ] ] ) p [ a [ m ] ] , s p [ i ] = ∑ m = 0 i p [ a [ m ] ] s[i]=\sum_{m=0}^i(m-p[a[m]])p[a[m]],sp[i]=\sum_{m=0}^ip[a[m]] s[i]=∑m=0i(m−p[a[m]])p[a[m]],sp[i]=∑m=0ip[a[m]], a = N M , p [ C i ] = P O S i a=NM,p[C_i]=POS_i a=NM,p[Ci]=POSi ,设 k 1 < k 2 k_1<k_2 k1<k2,且 k 2 k_2 k2 优于 k 1 k_1 k1,则:
d p [ k 2 ] [ j − 1 ] + s [ i ] − s [ k 2 ] − ( k 2 + 1 ) ( s p [ i ] − s p [ k 2 ] ) < d p [ k 1 ] [ j − 1 ] + s [ i ] − s [ k 1 ] − ( k 1 + 1 ) ( s p [ i ] − s p [ k 1 ] ) dp[k_2][j-1]+s[i]-s[k_2]-(k_2+1)(sp[i]-sp[k_2])<dp[k_1][j-1]+s[i]-s[k_1]-(k_1+1)(sp[i]-sp[k_1]) dp[k2][j−1]+s[i]−s[k2]−(k2+1)(sp[i]−sp[k2])<dp[k1][j−1]+s[i]−s[k1]−(k1+1)(sp[i]−sp[k1])
d p [ k 2 ] [ j − 1 ] − s [ k 2 ] + s p [ k 2 ] ( k 2 + 1 ) − ( d p [ k 1 ] [ j − 1 ] − s [ k 1 ] + s p [ k 1 ] ( k 1 + 1 ) ) < s p [ i ] ( k 2 − k 1 ) y k 2 − y k 1 x k 2 − x k 1 < s p [ i ] \begin{aligned} dp[k_2][j-1]-s[k_2]+sp[k_2](k_2+1)-(dp[k_1][j-1]-s[k_1]+sp[k_1](k_1+1))&<sp[i](k_2-k_1)\\ \frac{y_{k_2}-y_{k_1}}{x_{k_2}-x_{k_1}}&<sp[i] \end{aligned} dp[k2][j−1]−s[k2]+sp[k2](k2+1)−(dp[k1][j−1]−s[k1]+sp[k1](k1+1))xk2−xk1yk2−yk1<sp[i](k2−k1)<sp[i]
其中 y k = d p [ k ] [ j − 1 ] − s [ k ] + s p [ k ] ( k + 1 ) , x k = k y_k=dp[k][j-1]-s[k]+sp[k](k+1),x_k=k yk=dp[k][j−1]−s[k]+sp[k](k+1),xk=k。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
//#define WINE
#define MAXN 20010
using namespace std;
typedef long long ll;
int T,iCase,k,n,p[300],h,t,q[MAXN];
ll s[MAXN],sp[MAXN],dp[MAXN][505];
char PN[30],a[MAXN];
ll up(int k2,int k1,int j){
return dp[k2][j-1]-s[k2]+(k2+1)*sp[k2]-(dp[k1][j-1]-s[k1]+(k1+1)*sp[k1]);
}
ll down(int k2,int k1){
return k2-k1;
}
ll getDP(int k,int i,int j){
return dp[k][j-1]+s[i]-s[k]-(k+1)*(sp[i]-sp[k]);
}
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
scanf("%d",&T);
while(T--){
scanf(" %s %d",PN,&k);
scanf(" %s ",a);
int len=strlen(PN);
for(int i=0;i<len;i++)p[PN[i]]=i;
n=strlen(a);
for(int i=0;i<n;i++){
s[i]=(i==0)?0:s[i-1];
s[i]+=(i-p[a[i]])*p[a[i]];
sp[i]=(i==0)?0:sp[i-1];
sp[i]+=p[a[i]];
dp[i][1]=s[i];
}
for(int j=2;j<=k;j++){
h=t=0;q[t++]=j-2;
for(int i=j-1;i<n;i++){
while(h+1<t&&up(q[h+1],q[h],j)<sp[i]*down(q[h+1],q[h]))
h++;
dp[i][j]=getDP(q[h],i,j);
while(h+1<t&&up(i,q[t-1],j)*down(q[t-1],q[t-2])<=up(q[t-1],q[t-2],j)*down(i,q[t-1]))
t--;
q[t++]=i;
}
}
printf("Case %d: %lld\n",++iCase,dp[n-1][k]);
}
return 0;
}