逐月新星杯
B. 拓扑图计数
题目描述
给定一个排列 \(p\),求有多少个 DAG 的最小字典序拓扑序为 \(p\)。
思路
我们对于每个点 \(p_i\),考虑前面的点连到 \(p_i\) 的方案数。如果 \(i\) 前面没有有大于 \(p_i\) 的就随便选。而如果有,令其为 \(j\),那么 \(j\) 之前的还是照样随便选,但 \(j\) 之后至少要选一条边(因为 \(j\) 之后的一定都小于 \(p_j\))。
空间复杂度 \(O(N)\),时间复杂度最优 \(O(N)\)(但由于我弱智了,所以我是 \(O(N\log N)\))。
思路
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 200001, MOD = 998244353;
int n, tr[MAXN], ans = 1;
void update(int p, int x) {
for(; p <= n; tr[p] = max(tr[p], x), p += (p & -p)) {
}
}
int Getmax(int p) {
int Max = 0;
for(; p; Max = max(Max, tr[p]), p -= (p & -p)) {
}
return Max;
}
int Pow(int a, int b) {
int ret = 1;
for(; b; a = 1ll * a * a % MOD, b >>= 1) {
if(b & 1) {
ret = 1ll * ret * a % MOD;
}
}
return ret;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1, x; i <= n; ++i) {
cin >> x;
int last = Getmax(n - x + 1);
update(n - x + 1, i);
ans = 1ll * ans * (!last ? Pow(2, i - 1) : 1ll * Pow(2, last - 1) * (Pow(2, i - last) - 1 + MOD) % MOD) % MOD;
}
cout << ans;
return 0;
}
D. 括号子区间
题目描述
我们定义一个合法括号串为:
- 空串是合法括号串。
- 若 \(S\) 是合法括号串,则 \((S)\) 也是合法括号串。
- 若 \(S,T\) 是合法括号串,则 \(ST\) 也是合法括号串。
现在你要构造一个括号串 \(S\) 使得其满足尽可能多的以下条件:
- \(S[l_i:r_i]\) 是一个合法括号串。
求满足条件最大数量。
思路
我们考虑两个条件 \([l_i,r_i],[l_j,r_j]\) 是否能兼容,有三种情况:
- \([l_i,r_i]\cap[l_j,r_j]=\varnothing\),那么可以兼容。
- \([l_i,r_i]\cap[l_j,r_j]=[l_i,r_i]\or [l_i,r_i]\cap[l_j,r_j]=[l_j,r_j]\),由于题目保证了 \(r_i-l_i+1\) 为偶数,所以也可以兼容。
- 否则说明 \([l_i,r_i],[l_j,r_j]\) 相交,如果相交的长度为偶数那么可以兼容,否则不行。
由于相交且相交部分为奇数的情况一定满足其 \(l_i\) 奇偶性不同,所以一定是二分图。
最后跑一遍二分图最大匹配求出最大独立集即可。
空间复杂度 \(O(M^2)\),时间复杂度 \(O(M^2\sqrt M)\)。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 501;
int n, m, l[MAXN], r[MAXN], ans, pl[MAXN], pr[MAXN], dist[MAXN];
bool flag[MAXN], vis[MAXN];
vector<int> e[MAXN];
bool bfs() {
fill(vis + 1, vis + m + 1, 0);
fill(dist + 1, dist + m + 1, 0);
queue<int> que;
for(int i = 1; i <= m; ++i) {
if(l[i] % 2 && !pl[i]) {
que.push(i);
dist[i] = 1;
}
}
for(; !que.empty(); ) {
int u = que.front();
que.pop();
for(int v : e[u]) {
if(!pr[v]) {
return 1;
}
if(!dist[pr[v]]) {
dist[pr[v]] = dist[u] + 1;
que.push(pr[v]);
}
}
}
return 0;
}
bool dfs(int u) {
if(vis[u]) {
return 0;
}
vis[u] = 1;
for(int v : e[u]) {
if(!pr[v] || (dist[pr[v]] == dist[u] + 1 && dfs(pr[v]))) {
pl[u] = v, pr[v] = u;
return 1;
}
}
return 0;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m;
for(int i = 1; i <= m; ++i) {
cin >> l[i] >> r[i];
}
for(int i = 1; i <= m; ++i) {
for(int j = i + 1; j <= m; ++j) {
if((r[i] >= l[j] && r[i] < r[j] && l[i] < l[j] && (r[i] - l[j] + 1) % 2) || (r[j] >= l[i] && r[j] < r[i] && l[j] < l[i] && (r[j] - l[i] + 1) % 2)) {
if(l[i] % 2) {
e[i].emplace_back(j);
flag[j] = 1;
}else {
e[j].emplace_back(i);
}
}
}
}
for(; bfs(); ) {
for(int i = 1; i <= m; ++i) {
ans += (l[i] % 2 && !pl[i] && dfs(i));
}
}
cout << m - ans;
return 0;
}