这题状态转移方程倒是很好想,就是那个预处理有点麻烦,没办法最后还是百度......百度后还是T......
预处理方面,knm[i][j]表示n,m两个序列n取走i个m取走j个后已经开始且没有结束的颜色的花费.
刘汝佳标程里处理是先在i为0时扫一遍j,然后每个knm[i][j]的j部分就由上一层计算得来.
第二个卡我的点是memset,我因为它超时了,我觉得不应该啊,,,
先看刘汝佳滚动数组的写法,用 ^ 来滚动.而且是小数组memset不会超时.
// UVa1625 Color Length
// Rujia Liu
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 5000 + 5;
const int INF = 1000000000;
char p[maxn], q[maxn]; // starts from position 1
int sp[26], sq[26], ep[26], eq[26]; // sp[i] start positions of character i in p
int d[2][maxn], c[2][maxn]; // 滚动数组 c[i][j]: how many "incomplete" colors in the mixed sequence
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%s%s", p+1, q+1);
int n = strlen(p+1);
int m = strlen(q+1);
for(int i = 1; i <= n; i++) p[i] -= 'A';
for(int i = 1; i <= m; i++) q[i] -= 'A';
// calculate s and e
for(int i = 0; i < 26; i++)
{
sp[i] = sq[i] = INF;
ep[i] = eq[i] = 0;
}
for(int i = 1; i <= n; i++)
{
sp[p[i]] = min(sp[p[i]], i);
ep[p[i]] = i;
}
for(int i = 1; i <= m; i++)
{
sq[q[i]] = min(sq[q[i]], i);
eq[q[i]] = i;
}
// dp
int t = 0;
memset(c, 0, sizeof(c));
memset(d, 0, sizeof(d));
for(int i = 0; i <= n; i++)
{
for(int j = 0; j <= m; j++)
{
if(!i && !j) continue;
// calculate d
int v1 = INF, v2 = INF;
//计算d[i][j], d[i][j]由d[i-1][j]或d[i][j-1]添加一个字母得到
if(i) v1 = d[t^1][j] + c[t^1][j]; // remove from p
if(j) v2 = d[t][j - 1] + c[t][j - 1]; // remove from q
d[t][j] = min(v1, v2);
// calculate c
if(i)
{
c[t][j] = c[t^1][j];
if(sp[p[i]] == i && sq[p[i]] > j) c[t][j]++; //出现新的字母
if(ep[p[i]] == i && eq[p[i]] <= j) c[t][j]--; //一个字母已经结束
}
else if(j)
{
c[t][j] = c[t][j - 1];
if(sq[q[j]] == j && sp[q[j]] > i) c[t][j]++;
if(eq[q[j]] == j && ep[q[j]] <= i) c[t][j]--;
}
printf("%d %d %d\n", c[t][j], i, j);
}
t ^= 1;
}
printf("%d\n", d[t^1][m]);
}
return 0;
}
我T了的代码们:
/*
#include <bits/stdc++.h>
using namespace std;
#define INF 1000000
typedef pair<int, int> P;
#define f first
#define s second
int dp[5002][5002];
int knm[5002][5002];
int ln, lm;
char n[5005], m[5005];
P saen[30], saem[30];
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%s%s", n + 1, m + 1);
ln = strlen(n + 1), lm = strlen(m + 1);
for(int i = 0; i <= 26; i++){
saen[i].f = saem[i].f = INF;
saen[i].s = saem[i].s = 0;
}
for(int i = 1; i <= ln; i++){
n[i] -= 'A';
saen[n[i]].f = min(saen[n[i]].f, i);
saen[n[i]].s = i;
}
for(int i = 1; i <= lm; i++){
m[i] -= 'A';
saem[m[i]].f = min(saem[m[i]].f, i);
saem[m[i]].s = i;
}
memset(knm, 0, sizeof knm);
memset(dp, 0, sizeof dp);
for(int i = 0; i <= ln; i++){
for(int j = 0; j <= lm; j++){
if(!i && !j)
continue;
int v1 = INF, v2 = INF;
if(i) v1 = dp[i - 1][j] + knm[i - 1][j];
if(j) v2 = dp[i][j - 1] + knm[i][j - 1];
dp[i][j] = min(v1, v2);
if(i){
knm[i][j] = knm[i - 1][j];
if(saen[n[i]].f == i && saem[n[i]].f > j) knm[i][j]++;
if(saen[n[i]].s == i && saem[n[i]].s <= j) knm[i][j]--;
}
else if(j){
knm[i][j] = knm[i][j - 1];
if(saem[m[j]].f == j && saen[m[j]].f > i) knm[i][j]++;
if(saem[m[j]].s == j && saen[m[j]].s <= i) knm[i][j]--;
}
}
}
printf("%d\n", dp[ln][lm]);
}
return 0;
}
*/
/*
#include <bits/stdc++.h>
using namespace std;
#define INF 1000000
typedef pair<int, int> P;
#define f first
#define s second
int dp[5002][5002];
int knm[5002][5002];
int ln, lm;
char n[5005], m[5005];
P saen[30], saem[30];
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%s%s", n + 1, m + 1);
ln = strlen(n + 1), lm = strlen(m + 1);
for(int i = 0; i <= 26; i++){
saen[i].f = saem[i].f = INF;
saen[i].s = saem[i].s = 0;
}
for(int i = 1; i <= ln; i++){
int j = n[i] - 'A';
saen[j].f = min(saen[j].f, i);
saen[j].s = i;
}
for(int i = 1; i <= lm; i++){
int j = m[i] - 'A';
saem[j].f = min(saem[j].f, i);
saem[j].s = i;
}
memset(knm, 0, sizeof knm);
memset(dp, 0, sizeof dp);
for(int i = 0; i <= ln; i++)
for(int j = 0; j <= lm; j++)
{
if(i){
knm[i][j] = knm[i - 1][j];
if(saen[n[i] - 'A'].f == i && saem[n[i] - 'A'].f > j) knm[i][j]++;
if(saen[n[i] - 'A'].s == i && saem[n[i] - 'A'].s <= j) knm[i][j]--;
}
else if(j){
knm[i][j] = knm[i][j - 1];
if(saem[m[j] - 'A'].f == j && saen[m[j] - 'A'].f > i) knm[i][j]++;
if(saem[m[j] - 'A'].s == j && saen[m[j] - 'A'].s <= i) knm[i][j]--;
}
}
for(int i = 0; i <= ln; i++){
for(int j = 0; j <= lm; j++){
if(!i && !j)
continue;
int v1 = INF, v2 = INF;
if(i) v1 = dp[i - 1][j] + knm[i - 1][j];
if(j) v2 = dp[i][j - 1] + knm[i][j - 1];
dp[i][j] = min(v1, v2);
}
}
printf("%d\n", dp[ln][lm]);
}
return 0;
}
都是因为memsetT的,看了别人的代码,人家根本没有刷新数组,其实想一想真的不用,dp的边界dp[0][0]永远是0,knm的边界knm[0][0]也是.
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define INF 1000000
int dp[5002][5002];
int knm[5002][5002];
int ln, lm;
char n[5005], m[5005];
int sn[26], sm[26], en[26], em[26];
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%s%s", n + 1, m + 1);
ln = strlen(n + 1), lm = strlen(m + 1);
for(int i = 0; i <= 26; i++)
{
sn[i] = sm[i] = INF;
en[i] = em[i] = 0;
}
for(int i = 1; i <= ln; i++)
{
n[i] -= 'A';
sn[n[i]] = min(sn[n[i]], i);
en[n[i]] = i;
}
for(int i = 1; i <= lm; i++)
{
m[i] -= 'A';
sm[m[i]] = min(sm[m[i]], i);
em[m[i]] = i;
}
// memset(knm, 0, sizeof knm);
//memset(dp, 0, sizeof dp);
for(int i = 0; i <= ln; i++)
{
for(int j = 0; j <= lm; j++)
{
if(!i && !j)
continue;
int v1 = INF, v2 = INF;
if(i) v1 = dp[i - 1][j] + knm[i - 1][j];
if(j) v2 = dp[i][j - 1] + knm[i][j - 1];
dp[i][j] = min(v1, v2);
if(i)
{
knm[i][j] = knm[i - 1][j];
if(sn[n[i]] == i && sm[n[i]] > j) knm[i][j]++;
if(en[n[i]] == i && em[n[i]] <= j) knm[i][j]--;
}
else if(j)
{
knm[i][j] = knm[i][j - 1];
if(sm[m[j]] == j && sn[m[j]] > i) knm[i][j]++;
if(em[m[j]] == j && en[m[j]] <= i) knm[i][j]--;
}
}
}
printf("%d\n", dp[ln][lm]);
}
return 0;
}
再看看刘汝佳的滚动数组,婉转回肠地唉一声,,,,,,