P10008 [集训队互测 2022] Range Minimum Element
Genius_Star · · 题解
或许更好的阅读体验。
题意:
有一个长度为
求出
其中
思路:
这种题,直接做是困难的,就是考虑构造一组
对于一组固定的
于是一个
-
设
a 中第一个值为1 的位置为k ,即a_k = 1 ;此时所有跨过k 的区间的\min 都为1 ,暂时不需要管。 -
然后考虑左边
[1, k) 的部分,容易发现必须满足[1, k) 中的所有区间恰好完美覆盖了[1, k) ,因为如果没有完美覆盖,最后存在空位被赋值为1 就矛盾了;然后这边的值必须在[2, c] 范围内。 -
对于右边依然可以填任意的
[1, c] ,没有限制。
于是一个
那么可以想到 dp 的状态,即
- 若区间内没有
i :
- 否则枚举区间内出现的第一个
i :
这样做是
你手摸一下式子
于是只需要算出最大的
时间复杂度为
完整代码:
#include<bits/stdc++.h>
#define ls(k) k << 1
#define rs(k) k << 1 | 1
#define lowbit(x) x & (-x)
#define fi first
#define se second
#define popcnt(x) __builtin_popcount(x)
#define open(s1, s2) freopen(s1, "r", stdin), freopen(s2, "w", stdout);
using namespace std;
typedef __int128 __;
typedef long double lb;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
bool Begin;
const int N = 105, M = 1e4 + 10, mod = 998244353;
inline ll read() {
ll x = 0, dp = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-')
dp = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return x * dp;
}
inline void write(ll x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
inline void getadd(int &x, int y){
x = (x + y >= mod) ? (x + y - mod) : (x + y);
}
inline void getdec(int &x, int y){
x = (x < y) ? (x - y + mod) : (x - y);
}
int n, m, c;
int d[N], x[N], y[N], L[M], R[M];
int dp[N][N][N];
bool f[N][N];
inline int qpow(int a, int b){
int ans = 1;
while(b){
if(b & 1)
ans = 1ll * ans * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return ans;
}
inline int getf(int n, int k){
int sum = 0;
for(int i = 1; i <= n; ++i){
int a = 1, b = 1;
for(int j = 1; j <= n; ++j){
if(i == j)
continue;
a = 1ll * (k - x[j] + mod) % mod * a % mod;
b = 1ll * (x[i] - x[j] + mod) % mod * b % mod;
}
sum = (sum + 1ll * y[i] * a % mod * qpow(b, mod - 2) % mod) % mod;
}
return sum;
}
int main() {
n = read(), m = read(), c = read();
for(int i = 1; i <= m; ++i)
L[i] = read(), R[i] = read();
for(int l = 1; l <= n; ++l){
for(int r = l; r <= n; ++r){
for(int i = l - 1; i <= r + 1; ++i)
d[i] = 0;
for(int i = 1; i <= m; ++i)
if(l <= L[i] && R[i] <= r)
++d[L[i]], --d[R[i] + 1];
f[l][r] = 1;
for(int i = l; i <= r; ++i){
d[i] += d[i - 1];
if(!d[i]){
f[l][r] = 0;
break;
}
}
// cerr << f[l][r];
}
}
// cerr << '\n';
// cerr << f[1][2] << ' ' << f[1][1] << '\n';
for(int i = 1; i <= n + 1; ++i){
// cerr << i << '\n';
x[i] = c - i + 1;
for(int len = 1; len <= n; ++len){
for(int l = 1; l + len - 1 <= n; ++l){
int r = l + len - 1;
if(f[l][r])
getadd(dp[i][l][r], dp[i - 1][l][r]);
if(l == r)
getadd(dp[i][l][r], 1);
else
getadd(dp[i][l][r], dp[i][l + 1][r]);
if(f[l][r - 1])
getadd(dp[i][l][r], dp[i - 1][l][r - 1]);
for(int k = l + 1; k < r; ++k)
if(f[l][k - 1])
getadd(dp[i][l][r], 1ll * dp[i - 1][l][k - 1] * dp[i][k + 1][r] % mod);
// cerr << " " << l << ' ' << r << ' ' << dp[i][l][r] << '\n';
}
// cerr << '\n';
}
// cerr << '\n' << '\n';
y[i] = dp[i][1][n];
// cerr << y[i] << '\n';
}
if(c <= n + 1){
write(y[c]);
putchar('\n');
return 0;
}
write(getf(n + 1, 1));
return 0;
}