Excavations
dp #性质
一个集合 \(s\) 满足条件,当且仅当 \(\forall x\in s, mindep_x<min_{y\notin s}mindep_y\)
枚举后面的那个,\(dp_i\) 表示前面选择 \(i\) 个的方案数,转移看code
// Author: xiaruize
const int N = 50 + 10;
int n, k;
struct node
{
int kd, dep;
} s[N];
int m;
bool vis[N];
int cnt[N], cur[N];
int dp[N];
int tot = 0;
int c[N][N];
int tmp[N];
bool cmp(node a, node b)
{
if (a.dep != b.dep)
return a.dep < b.dep;
return vis[a.kd] < vis[b.kd];
}
void solve()
{
cin >> n;
rep(i, 1, n)
{
cin >> s[i].kd;
cnt[s[i].kd]++;
tot = max(tot, s[i].kd);
}
cin >> n;
rep(i, 1, n) cin >> s[i].dep;
cin >> m;
rep(i, 1, m)
{
int x;
cin >> x;
vis[x] = true;
}
rep(i, 0, 50)
{
c[i][0] = c[i][i] = 1;
rep(j, 1, i - 1)
c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
}
cin >> k;
sort(s + 1, s + n + 1, cmp);
int res = 0;
rep(i, 1, n)
{
cnt[s[i].kd]--;
if (!vis[s[i].kd])
continue;
mms(dp, 0);
dp[1] = 1;
rep(j, 1, tot)
{
memcpy(tmp, dp, sizeof(dp));
mms(dp, 0);
rep(p, 1, k)
{
rep(q, 0, min(cnt[j], k - p))
{
dp[p + q] += c[cnt[j]][q] * tmp[p];
}
}
if (vis[j] && s[i].kd != j)
{
memcpy(tmp, dp, sizeof(dp));
mms(dp, 0);
rep(p, 1, k)
{
rep(q, 1, min(cur[j], k - p))
{
dp[p + q] += c[cur[j]][q] * tmp[p];
}
}
}
}
cur[s[i].kd]++;
res += dp[k];
}
cout << res << endl;
}
#ifndef ONLINE_JUDGE
bool end_of_memory_use;
#endif
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase = 1;
// cin >> testcase;
while (testcase--)
solve();
#ifndef ONLINE_JUDGE
cerr << "Memory use:" << (&end_of_memory_use - &start_of_memory_use) / 1024.0 / 1024.0 << "MiB" << endl;
cerr << "Time use:" << (double)clock() / CLOCKS_PER_SEC * 1000.0 << "ms" << endl;
#endif
return 0;
}