BZOJ 1789&1830 推式子 乱搞
把思路理顺了就行了… 下面把整个乱搞思路讲一下。
三条项链首先考虑最里面的那个珠子。如果不是完全相同的话,就需要把所有项链的所有珠子全都拆下来——这也就是全部过程,如果再装的话也是浪费。然后如果完全相同的话,就考虑倒数第二个珠子,一样的思维方式。因此,我们要找到的就是从里到外第一个不完全相同的珠子,这一段可以直接忽略。
然后我们先考虑两条项链的情形:很明显,最优方案就是一直拆,拆到完全相同为止。然后我们加入第三条项链,这时候也要一直拆,一直拆到底(因为经过之前的步骤,三条项链的最里面的珠子不完全相同),然后往回补,一直补到前两条项链的最长公共前缀处。这样不难证明是最优的。这时,$$Ans=Len_A+Len_B+Len_C-d$$其中\(d\)是前两条相连的最大公共前缀。最后的问题就是谁是“前两条项链”——枚举即可,取\(d\)的最大值,即可获得\(Ans\)的最小。这道题的思考方式和1787有点像(那题是三个点的LCA),也是AHOI的题。
代码的细节需要注意(略丑…)
// BZOJ 1789
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define rep(i,a,b) for (int i=a; i<=b; i++)
#define read(x) scanf("%d", &x)
const int INF=0x3f3f3f3f;
char st[4][50+5];
int same, len[4];
int check(int x, int y) {
int ret=1;
if (len[x]>len[y]) swap(x, y);
while (ret+same<=len[x] && st[x][ret+same]==st[y][ret+same]) ret++;
return ret-1;
}
int main()
{
int ml=INF;
rep(i,1,3) read(len[i]), ml=min(ml, len[i]), scanf("%s", st[i]+1);
rep(i,1,ml)
if (!((st[1][i]==st[2][i]) && (st[1][i]==st[3][i]))) break; else same=i;
int d=max(max(check(1, 2), check(1, 3)), check(2, 3));
int ans=len[1]+len[2]+len[3]-d-3*same;
printf("%d\n", ans);
}