洛谷P4063 [JXOI2017]数列(dp)
程序员文章站
2022-04-28 11:41:48
题意 "题目链接" Sol 这题想还是不难想的,就是写起来很麻烦,然后去看了一下loj的最短代码表示只能Orz 首先不难发现一条性质:能够选择的区间一定是不断收缩的,而且新的可选区间一定是旧区间的某个位置划分而来的。 比如$A_{i 1} = x$,此时小于$x$的最大数为$l_{i 1}$,大于$ ......
题意
sol
这题想还是不难想的,就是写起来很麻烦,然后去看了一下loj的最短代码表示只能orz
首先不难发现一条性质:能够选择的区间一定是不断收缩的,而且新的可选区间一定是旧区间的某个位置划分而来的。
比如\(a_{i-1} = x\),此时小于\(x\)的最大数为\(l_{i-1}\),大于\(x\)的最小数为\(r_{i-1}\),我在这之中选了一个\(a_i = t\),那么我们考虑\(a_{i+1}\)的时候。显然若\(t < x\),那么大于\(t\)的最小数为\(x\),小于\(t\)的最大数为\(l\),\(t>x\)同理。
然后就可以设\(f[i][l][r]\)表示\(i\)位置在\([l,r]\)内取值的方案数。转移的时候需要倒着转移。
直接记忆话搜索即可
复杂度\(o(nr^3)\)
#include<bits/stdc++.h> #define fin(x) freopen(#x".in", "r", stdin); using namespace std; const int maxn = 50001, mod = 998244353; template<typename a, typename b> inline bool chmax(a &x, b y) {return x < y ? x = y, 1 : 0;} template<typename a, typename b> inline bool chmin(a &x, b y) {return x > y ? x = y, 1 : 0;} template<typename a, typename b> inline a mul(a x, b y) {return 1ll * x * y % mod;} template<typename a, typename b> inline void add2(a &x, b y) {x = x + y >= mod ? x + y - mod : x + y;} template<typename a, typename b> inline int add(a x, b y) {return x + y >= mod ? x + y - mod : x + y;} inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } int n, a[51], f[51][152][152]; int dfs(int x, int l, int r) { if(x > n) return 1; int &res = f[x][l][r]; if(~res) return res; res = 0; for(int i = max(1, l); i <= min(a[x], r); i++) { if(i == l || i == r) add2(res, dfs(x + 1, i, i)); else add2(res, add(add(dfs(x + 1, l, i), dfs(x + 1, i, r)), -dfs(x + 1, i, i) + mod)); } return res; } signed main() { memset(f, -1, sizeof(f)); n = read(); int mx = 0; for(int i = 1; i <= n; i++) a[i] = read(), chmax(mx, a[i]); cout << dfs(1, 0, mx + 1); return 0; }
上一篇: Hibernate知识总结(一)