easy:注意consecutive这个词,给同一个人要连续的几段啊。。。。尼玛没有看到啊。。。。然后有了这个词,就可以直接暴力标记那些位置要切。
medium:先把奇数度的点配对,变成个欧拉回路,然后跑一遍,这样不要加的变,每个奇度点才会有1的cost,偶度点都没有,这样显然最小。
hard:长度为25保证总有一个没出现过的字符,这样我们就可以一位一位贪心,每一位靠dp得到上下界(后面没确定的全部设为通配符或者没出现过即全都不匹配,得到上下届,need在上下界这一位就选那个字符),枚举lcs,枚举每一位,枚举每一位选的字母,然后做lcs,总复杂度是n^4*m
(十分感谢safarisoul教会我了n^3*m的做法!她的题解:http://topcoder-algorithm.blogspot.com.au/2014/04/srm517-div1-800-farstrings.html)
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>
using namespace std;
class FarStrings {
public:
vector<string> find(string);
};
int dp[30][30];
bool eq(char a, char b) {
if (a == 'A')
return true;
return a == b;
}
int lcs(string s, string t) {
int i, j, k;
int n;
memset(dp, 0, sizeof(dp));
n = s.size();
for (i = 0; i <= n; ++i) {
dp[i][0] = i;
dp[0][i] = i;
}
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
if (eq(s[i], t[j]))
dp[i + 1][j + 1] = dp[i][j];
else {
dp[i + 1][j + 1] = min(dp[i][j + 1] + 1, min(dp[i + 1][j] + 1,
dp[i][j] + 1));
}
}
}
return dp[n][n];
}
vector<string> FarStrings::find(string t) {
int i, j, k;
vector<string> ret;
string s, p;
int n;
n = t.size();
for (i = 1; i <= n; ++i) {
s.clear();
p.clear();
for (j = 0; j < n; ++j) {
s.push_back('A');
p.push_back('B');
}
for (j = 0; j < n; ++j) {
for (k = 0; k < 26; ++k) {
s[j] = k + 'a';
p[j] = k + 'a';
if (i >= lcs(s, t) && i <= lcs(p, t))
break;
}
}
ret.push_back(s);
}
return ret;
}
挖个坑, safarisoul提供了两份资料,貌似能更优?还没来得及看
http://dl.acm.org/citation.cfm?id=214183
http://link.springer.com/chapter/10.1007%2FBFb0030777