SRM 617

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

你可能感兴趣的:(topcoder,SRM)