Loading

[AGC056B] Range Argmax

发现一个序列 x 不止可以用一个 p 得到,肯定不能直接计数,考虑构造一个映射。

假如已经定下了 x,我们通过一种固定的操作得到 p,这样就能改为统计可以由操作得到的 p 的数量,他们同样唯一对应一个 x

我们考虑枚举从 n1 去枚举 v,对每个 v 找到一个能找到的最左边的点赋值。一个位置 pos 能赋值 v 当且仅当所有 li,ri 包含 posxi 等于 pos

接下来我们就可以处理左区间和右区间的位置了。容易发现其右边的值都要小于左边的值,这将变成两个子问题。

现在 x 并不固定,我们需要分析条件才能计数。

注意到,若当前我们在 pos 这里赋值,那么对于左侧的最大值的位置 k,一定存在一个区间满足 likposri,因为若没有区间同时包含 k,pos,那么显然我可以让 ppos=v,所以一定存在这样的区间。之所以存在这种情况那只能是因为这个区间的 xi 等于 pos。我们需要用一个大数在这里填,填完以后再将区间删去才能更新 k

这启发我们进行一个区间 dp,设 fl,r,i 表示在区间 l,r 中最大值位置在 i 的方案数。但是由于这样子复杂度很劣,我们将状态改为在区间 l,r 中最大值位置大于等于 i 的方案数就能 O(n3) 解决问题了,具体就是先维护区间如果要选 pos 赋值,包含 pos 的区间的最小 li,然后再后缀和转移即可。

代码:

#include <bits/stdc++.h>
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; ++ i)
#define rrp(i, l, r) for (int i = r; i >= l; -- i)
#define pii pair <int, int>
#define eb emplace_back
#define id(x, y) n * (x - 1) + y
#define ls p << 1
#define rs ls | 1
using namespace std;
constexpr int N = 300 + 5, M = (1ll << 31) - 1, P = 998244353;
constexpr double PI = acos (-1.0);
inline int rd () {
  int x = 0, f = 1;
  char ch = getchar ();
  while (! isdigit (ch)) {
    if (ch == '-') f = -1;
    ch = getchar ();
  }
  while (isdigit (ch)) {
    x = (x << 1) + (x << 3) + ch - 48;
    ch = getchar ();
  }
  return x * f;
}
int qpow (int x, int y) {
  int ret = 1;
  for (; y; y >>= 1, x = x * x % P) if (y & 1) ret = ret * x % P;
  return ret;
}
int f[N][N][N], g[N][N][N];
int n, m;
long long fac[N], ifac[N];
int C (int n, int m) {
  if (m < 0 || m > n) return 0;
  return fac[n] * ifac[m] % P * ifac[n - m] % P;
}
int l[N * N], r[N * N];
signed main () {
  // freopen ("1.in", "r", stdin);
  // freopen ("1.out", "w", stdout);
  n = rd (), m = rd ();
  rep (i, 1, m) l[i] = rd (), r[i] = rd ();
  rep (i, 0, n + 1) rep (j, 0, n + 1) rep (k, 0, n + 1) g[i][j][k] = n + 1;
  rep (i, 1, m) {
    rep (j, l[i], r[i]) {
      g[l[i]][r[i]][j] = min (g[l[i]][r[i]][j], l[i]); 
    }
  }
  rep (len, 1, n) {
    rep (l, 1, n - len + 1) {
      int r = l + len - 1;
      rep (k, 1, n) g[l][r][k] = min (g[l][r][k], min (g[l + 1][r][k], g[l][r - 1][k]));
    }
  }
  rep (l, 1, n + 1) rep (k, 1, n + 1) f[l][l - 1][k] = 1;
  rep (len, 1, n) {
    rep (l, 1, n - len + 1) {
      int r = l + len - 1;
      rrp (k, l, r) {
        (f[l][r][k] += f[l][r][k + 1] + f[l][k - 1][g[l][r][k]] * f[k + 1][r][k + 1]) %= P;
      }
    }
  } cout << f[1][n][1];
}

作者:lalaouye

出处:https://www.cnblogs.com/lalaouyehome/p/18446270

版权:本作品采用「114514」许可协议进行许可。

posted @   lalaouye  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示