SRM599Hard

题意

给定 \(n\) 个不相同的字符串,用 \(1\ ~\ n\) 给它们标号。有 \(m\) 个形如标号为 \(i\) 的要在标号为 \(j\) 的前面的限制。
问有多少种不同的标号方案,\(mod\ 10^9\ +\ 7\) 输出。

\(1\ \leq\ n\ \leq\ 50,\ 1\ \leq\ m\ \leq\ 8\)

做法1

对字符串建出前缀树,然后在树上背包dp。合并背包时只枚举合法的子集合并,可以发现总共只有 \(O(5^m)\) 种转移,因为对于一个限制 \(i,\ j\) 在两个合法子集 \(S,\ T\) 中,只有 \(5\) 种情况:

  1. \(i,\ j\) 均未出现在 \(S,\ T\)
  2. \(j\) 出现在 \(S\) 中,\(i\) 未出现
  3. \(i,\ j\) 出现在 \(S\)
  4. \(j\) 出现在 \(T\) 中,\(i\) 未出现
  5. \(i,\ j\) 出现在 \(T\)
    时间复杂度 \(O(n\ 5^m)\)
    实现的时候可以先预处理,枚举 \(5^m\) 种情况,然后将合法的用个 vector 存下,转移时直接转移 vector 中存的方案。

代码

#line 2 "SimilarNames.cpp"
#include <bits/stdc++.h>

#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif

#ifdef __WIN32
#define LLFORMAT "I64"
#define Rand() ((rand() << 15) + rand())
#else
#define LLFORMAT "ll"
#define Rand() (rand())
#endif


using namespace std;

class SimilarNames {
	public:
	int count(vector <string> names, vector <int> info1, vector <int> info2) ;
	
// BEGIN CUT HERE
	public:
	void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); if ((Case == -1) || (Case == 5)) test_case_5(); }
	private:
	template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
	void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
	void test_case_0() { string Arr0[] = {"kenta", "kentaro", "ken"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {0}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {1}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 3; verify_case(0, Arg3, count(Arg0, Arg1, Arg2)); }
	void test_case_1() { string Arr0[] = {"hideo", "hideto", "hideki", "hide"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {0, 0}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {1, 2}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 6; verify_case(1, Arg3, count(Arg0, Arg1, Arg2)); }
	void test_case_2() { string Arr0[] = {"aya", "saku", "emi", "ayane", "sakura", "emika", "sakurako"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {0, 1, 3, 5}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {1, 2, 4, 6}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 2; verify_case(2, Arg3, count(Arg0, Arg1, Arg2)); }
	void test_case_3() { string Arr0[] = {"taro", "jiro", "hanako"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {0, 1}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {1, 0}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 0; verify_case(3, Arg3, count(Arg0, Arg1, Arg2)); }
	void test_case_4() { string Arr0[] = {"alice", "bob", "charlie"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 6; verify_case(4, Arg3, count(Arg0, Arg1, Arg2)); }
	void test_case_5() { string Arr0[] = {"ryota", "ryohei", "ryotaro", "ryo", "ryoga", "ryoma", "ryoko", "ryosuke", "ciel", "lun",
 "ryuta", "ryuji", "ryuma", "ryujiro", "ryusuke", "ryutaro", "ryu", "ryuhei", "ryuichi", "evima"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); int Arr1[] = {17, 5, 6, 13, 5}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {9, 2, 14, 17, 14}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 994456648; verify_case(5, Arg3, count(Arg0, Arg1, Arg2)); }

// END CUT HERE

} ___test;

// BEGIN CUT HERE
int main() {
	int test_case;
	scanf("%d", &test_case);
	___test.run_test(test_case);
}
// END CUT HERE

//----------head----------

const int maxn = 55, maxm = 9, maxs = (1 << 16) | 10, mod = 1e9 + 7;

int n, m, k, dp[maxn][maxs], pw5[maxm], hsh[maxn], S;
vector<int> ok[maxs];
vector<pair<int, int> > all;
vector<int> g[maxn];

void dfs(int u) {
	static int pd[maxs];
	dp[u][0] = 1;
	for (int v: g[u]) {
		dfs(v);
		memset(pd, 0, sizeof(pd[0]) * S);
		for (auto &t: all) {
			int &x = t.first, &y = t.second, z = x | y;
			pd[z] = ((long long) dp[u][x] * dp[v][y] + pd[z]) % mod;
		}
		memcpy(dp[u], pd, sizeof(dp[u][0]) * S);
	}
	if(u) {
		memset(pd, 0, sizeof(pd[0]) * S);
		for (int t, s = 0; s < S; ++s) if(t = dp[u][s]) {
			pd[s] = (pd[s] + t) % mod;
			for (int r: ok[s]) pd[r] = (pd[r] + t) % mod;
		}
		memcpy(dp[u], pd, sizeof(dp[u][0]) * S);
	}
	return;
}

int SimilarNames::count(vector <string> names, vector <int> info1, vector <int> info2) {
	n = names.size(); m = info1.size(); k = 0;
	memset(dp, 0, sizeof dp); all.clear(); memset(hsh, -1, sizeof hsh);
	for (int i = 0; i <= n; ++i) g[i].clear();
	pw5[0] = 1; for (int i = 1; i <= m; ++i) pw5[i] = pw5[i - 1] * 5 % mod;
	for (int i = 0; i < m; ++i) {
		if(!~hsh[info1[i]]) hsh[info1[i]] = k++;
		if(!~hsh[info2[i]]) hsh[info2[i]] = k++;
		info1[i] = hsh[info1[i]];
		info2[i] = hsh[info2[i]];
	}
	for (int s = 0; s < pw5[m]; ++s) {
		int x = 0, y = 0;
		for (int i = 0; i < m; ++i) {
			int t = s / pw5[i] % 5;
			if(t == 1) x |= (1 << info2[i]);
			if(t == 2) x |= (1 << info1[i]) | (1 << info2[i]);
			if(t == 3) y |= (1 << info2[i]);
			if(t == 4) y |= (1 << info1[i]) | (1 << info2[i]);
		}
		if(!(x & y)) all.push_back(make_pair(x, y));
	}
	sort(all.begin(), all.end()); all.resize(unique(all.begin(), all.end()) - all.begin());
	names.push_back("");
	sort(names.begin(), names.end(), [&](string s, string t) { return s.size() < t.size(); });
	for (int i = 1; i <= n; ++i) {
		for (int j = i - 1; ~j; --j) if(names[i].substr(0, names[j].size()) == names[j]) { g[j].push_back(i); break; }
	}
	S = 1 << k;
	for (int s = 0; s < S; ++s) {
		ok[s].clear();
		for (int x = 0; x < k; ++x) if(!((s >> x) & 1)) {
			bool flag = 1;
			for (int i = 0; i < m; ++i) if(info1[i] == x && !((s >> info2[i]) & 1)) { flag = 0; break; }
			if(flag) ok[s].push_back(s | (1 << x));
		}
	}
	dfs(0);
	int ans = dp[0][S - 1];
	for (int i = 1; i <= n - k; ++i) ans = (long long) ans * i % mod;
	return ans;
}
posted @ 2018-09-01 11:22  King_George  阅读(175)  评论(0编辑  收藏  举报