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\) 种情况:
- \(i,\ j\) 均未出现在 \(S,\ T\) 中
- \(j\) 出现在 \(S\) 中,\(i\) 未出现
- \(i,\ j\) 出现在 \(S\) 中
- \(j\) 出现在 \(T\) 中,\(i\) 未出现
- \(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;
}