[ARC146E] Simple Speed

简单的操作分析题。

一些基础想法

首先,注意到直接怼着序列,不好计数。考虑按照值域从小到大计数。

假若不考虑边界(或者我们令 \(B_0=B_{N+1}=N+1\)),那么每次的段数是固定的。

具体的,元素 \(1\) 的所有数形成了 \(a_1\) 个不能相交的段,其中每个段两端都需要两个元素 \(2\)。但是两个段假若相邻,则可以共用一个 \(2\) 元素。

容易发现,此时在完成所有元素 \(2\) 的插入后,必定是形如一些类似 212,2121212 以及单独 2 的段。
这些段都满足:每段的元素 \(2\) 个数都比元素 \(1\) 个数多 \(1\)

故而每次容易算出有多少个新的段。而考虑到当前值域的所有元素和段时,我们往往只关心段数,因为这些段在后面计算的时候没有本质区别。

而如何组合拼接这些的段,可以用一个组合数直接完成。

正确的做法

但是现在考虑到两端都存在边界。

换句话说,比如当前有 \(5\) 个元素 \(1\) ,要插入 \(7\) 个元素 \(2\)

按照上面的想法,一种可行方案是 21212,2121212,它现在的段数是 \(a_2-a_1=7-5=2\)

当然,实际上还存在其它分配方案,比如 1212,212,21212
但是在这种方案中,第一段它的两端就不全是 \(2\) 了,换句话说,它现在只能放在最终序列的左边界。

注意到边界只有左、右两个。

故而我们记 \(f_{i,j=0\sim 2,k}\) 表示,考虑了值域为 \(1\sim i\) 的所有数,左右边界中已经被占据的边界有 \(j\) 个,最终形成了 \(k\) 个两端都是元素 \(i\) 的段。

这里的 \(k\) 只有 \(O(1)\) 个,可以轻松通过。

代码

#include <bits/stdc++.h>
#define FL(i, a, b) for (int i = (a); i <= (b); ++i)
#define FR(i, a, b) for (int i = (a); i >= (b); --i)
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
constexpr int N = 2e5 + 10, V = 2e5;
constexpr int mod = 998244353;
int n, cnt[N];
int inv[N], fac[N], ifac[N];
unordered_map<int, int> f[N][3];
inline void AddTo(int &x, const int &y) {
    x += y;
    x -= (x >= mod? mod : 0);
}
void Init() {
    fac[0] = ifac[0] = 1;
    FL(i, 1, V) {
        inv[i] = (i == 1? 1 : (ll)inv[mod % i] * (mod - mod / i) % mod);
        fac[i] = (ll)fac[i - 1] * i % mod;
        ifac[i] = (ll)ifac[i - 1] * inv[i] % mod;
    }
}
int C(int n, int m) {
    if (n < m || m < 0) {
        return 0;
    }
    return (ll)fac[n] * ifac[n - m] % mod * ifac[m] % mod;
}
int main() {
    Init();
    scanf("%d", &n);
    FL(i, 1, n) {
        scanf("%d", &cnt[i]);
    }
    f[1][2][cnt[1] - 1] = 1;
    FL(i, 2, n) {
        FL(a, 0, 2) {
            FL(c, a, 2) {
                for (auto x: f[i - 1][c]) {
                    int u = x.fi + a, v = x.se;
                    if (cnt[i] < u) continue;
                    int tmp = (ll)v * C(cnt[i] - 1, u - 1) % mod;
                    if (c == 2 && a == 1) {
                        tmp = tmp * 2 % mod;
                    }
                    AddTo(f[i][a][cnt[i] - u], tmp);
                }
            }
        }
    }
    int ans = 0;
    FL(a, 0, 2) {
        AddTo(ans, f[n][a][0]);
    }
    printf("%d\n", ans);
	return 0;
}
posted @ 2025-02-25 15:00  徐子洋  阅读(10)  评论(0)    收藏  举报