多校冲刺 NOIP 20211111 模拟 (28)


T1

\(f_{i,j}\)表示剩下i瓜子,j瓜子壳的期望步数

逆推转移即可

T2

发现k很小,考虑倒序枚举i,链表维护大于i的数

然后暴力跳左边和右边k个大于i的数即可

代码

T1

#include 
using namespace std;
#define int long long
const int N = 4e3 + 11;
const int mod = 998244353;
int n;
int inv[N];
int jc[N], ny[N];
int f[N / 2][N];
inline void md(int& x) {
    if (x >= mod)
        x -= mod;
    return;
}
int fm(int x, int y) {
    int ans = 1;
    for (; y; y >>= 1, x = x * x % mod)
        if (y & 1)
            ans = ans * x % mod;
    return ans;
}
void pre() {
    jc[0] = ny[0] = 1;
    inv[0] = inv[1] = 1;
    for (int i = 1; i <= 4e3; ++i) jc[i] = jc[i - 1] * i % mod;
    ny[(int)4e3] = fm(jc[(int)4e3], mod - 2);
    for (int i = 4e3 - 1; i; --i) ny[i] = ny[i + 1] * (i + 1) % mod, inv[i + 1] = jc[i] * ny[i + 1] % mod;
    return;
}
signed main() {
    FILE* x = freopen("eat.in", "r", stdin);
    x = freopen("eat.out", "w", stdout);
    //	for(int i=1;i<=100;++i)for(int j=1;j<=100;++j) if(i*fm(j,mod-2)%mod==332748119) cout<> n;
    for (int ed, i = 1; i <= n; ++i) {
        ed = 2 * (n - i);
        md(f[i][0] += (1 + f[i - 1][2]) % mod);
        for (int j = 1; j <= ed; ++j) {
            md(f[i][j] += j * (1 + f[i][j - 1]) % mod * inv[i + j] % mod);
            md(f[i][j] += i * (f[i - 1][j + 2] + 1) % mod * inv[i + j] % mod);
        }
    }
    cout << f[n][0] << endl;
    return 0;
}

T2

#include 
#include 
using namespace std;
const int N = 5e5 + 11;
int n, k;
int a[N], rle[N];
int top, sta[N];
int suml[52], numl, sumr[52], numr;
int rnxt[N], lnxt[N];
int l[N], r[N];
long long ans;
inline int read() {
    int s = 0;
    char ch = getchar();
    while (ch > '9' || ch < '0') ch = getchar();
    while (ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s;
}
void add(int i) {
    int loc = rle[i];
    l[loc] = lnxt[i], r[loc] = rnxt[i];
    r[l[loc]] = loc, l[r[loc]] = loc;
    return;
}
void js(int x) {
    int val = 0;
    numl = numr = 0;
    memset(suml, 0, sizeof(suml));
    memset(sumr, 0, sizeof(sumr));
    add(x);
    for (int sl = 1, i = rle[x]; i && sl <= k; i = l[i], ++sl) suml[++numl] = i - l[i];
    for (int sl = 1, i = rle[x]; i && sl <= k; i = r[i], ++sl) sumr[++numr] = (r[i] ? r[i] : n + 1) - i;
    for (int wz, i = 1; i <= numl; ++i) {
        wz = k - i + 1;
        if (wz > numr)
            continue;
        ans += 1ll * suml[i] * sumr[wz] * x;
    }
    return;
}
int main() {
    FILE* x = freopen("kth.in", "r", stdin);
    x = freopen("kth.out", "w", stdout);
    n = read();
    k = read();
    for (int i = 1; i <= n; ++i) {
        rle[a[i] = read()] = i;
        while (top && a[sta[top]] < a[i]) --top;
        lnxt[a[i]] = sta[top];
        sta[++top] = i;
    }
    top = 0;
    for (int i = n; i; --i) {
        while (top && a[sta[top]] < a[i]) --top;
        rnxt[a[i]] = sta[top];
        sta[++top] = i;
    }
    for (int loc, i = n; i > n - k + 1; --i) add(i);
    for (int i = n - k + 1; i; --i) js(i);
    cout << ans << endl;
    return 0;
}