逐月新星杯

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;
}
posted @ 2024-10-23 19:58  Yaosicheng124  阅读(2)  评论(0编辑  收藏  举报