SOJ 2775: Breaking Strings
Description
A certain string-processing language allows the programmer to break a string into two pieces. Since this involves copying the old string,
it costs n units of time to break a string of n characters into two pieces. Suppose a programmer wants to break a string into many pieces.
The order in which the breaks are made can affect the total amount of time used. For example, suppose we wish to break a 20 character string
after characters 3, 8, and 10 (numbering the characters in ascending order from the left-hand end, starting from 1). If the breaks are made
in left-to-right order, then the first break cost 20 units of time, the second break costs 17 units of time, and the third breaks costs 12
units of time, a total of 49 units of time (see the sample below). If the breaks are made in right-to-left order, then the first break costs
20 units of time, the second break costs 10 units of time, and the third break costs 8 units of time, a total of 38 units of time.
The cost of making the breaks in left-to-right order:
thisisastringofchars (original)
thi sisastringofchars (cost:20 units)
thi sisas tringofchars (cost:17 units)
thi sisas tr ingofchars (cost:12 units)
Total: 49 units.
The cost of making the breaks in right-to-left order:
thisisastringofchars (original)
thisisastr ingofchars (cost:20 units)
thisisas tr ingofchars (cost:10 units)
thi sisas tr ingofchars (cost: 8 units)
Total: 38 units.
Input
There are several test cases! In each test case, the first line contains 2 integers N (2<=N<=10000000) and M (1<=M<=1000, M < N ). N is the
original length of the string, and M is the number of the breaks. The following lines contain M integers Mi (1 <= Mi < N) in ascending order
that represent the breaking positions from the string's left-hand end.
Output
For each test case, output in one line the least cost to make all the breakings.
Sample Input
20 3
3 8 10
Sample Output
37
思路:
这道题可以用动态规划,先写出状态转移方程
f[i][j]=max{f[i][k]+f[k+1][j]}+d[i][j]
需要遍历k取最优值,预计复杂度会达到O(n^3),必然要超时…
观察方程,发现该题与凸四边优化的适用类型方程相似,接下来就是证明dp数组的单调性,列一个简单的比较不等式就可证得(当时是看到蓝色星空上的分类才去用凸四边不等式做的…)
之后的工作就非常简单了,引入决策点记录数组k[][],通过点调性进行优化,决策区间不重叠复杂度降至O(n^3)(其实应该还可以更优的,同样的方法不知为什么另一道类似的题目依旧超时…)
#include <stdio.h> int d[1002][1002]; int f[1002][1002]; int kn[1002][1002]; int kt; int main(){ int n,s[1002],m,t,i,j,k; while(scanf("%d %d",&n,&m)==2){ s[0]=0; for (i=1;i<=m;i++)scanf("%d",&s[i]); s[m+1]=n; for (i=0;i<=m;i++) f[i][i+1]=0; for (i=0;i<=m-1;i++){ f[i][i+2]=s[i+2]-s[i]; kn[i][i+2]=i+1; } for (i=3;i<=m+1;i++) for (j=0;j<=m+1-i;j++){ kt=kn[j][i+j-1]; t=f[j][kt]+f[kt][i+j]; for (k=kn[j][i+j-1];k<=kn[j+1][i+j];k++)//这里的区间不重合 if(f[j][k]+f[k][i+j]<t){ t=f[j][k]+f[k][i+j]; kt=k; } kn[j][i+j]=kt; //题目关键,记录决策点 f[j][i+j]=t+s[i+j]-s[j]; } printf("%d\n",f[0][m+1]); } return 0; }