Educational Codeforces Round 160 (Rated for Div. 2)(D 动态规划)
2023-12-20 01:11:22
关于如何思考DP这件事...这题还是比较好的
思路:考虑为当前共有 i 个数且以为结尾,能够形成的字段的个数。要想求出,只需要知道的前一个数可以是什么,这样就能够进行状态转移了。
首先定义是前方第一个比小的数。
1、首先考虑比还要大的数:如果一次操作中是最小的话,那么就能够删掉前面的数。因此的前一个数可以是。
2、接下来考虑的是比还要小的数,可以发现是可以被替换掉的。只需要找到前方第一个比它小的数,那么就会被替换掉。如此往复直到没有比它还要小的数为止。
接下来考虑如何去快速求解:
1、对于而言,需要找到前方第一个比还要小的数的下标,这一点可以用单调栈来实现。
2、对范围内的数,可以用前缀和来快速求解。
3、对于第二种情况,它并不是连续的一些数,但是可以发现这些数都是固定的,不会随着后面的数到来而改变,因此也可以化简成一个DP,从而快速转移。
最终考虑可达数组的个数:并不是以 i 结尾就一定能构成可达数组,必须要满足后方没有比它还要大的数才行,否则就永远不可能成为最终数组的最后一个,这个判断只需要反向整一个单调栈就行了。
// Problem: D. Array Collapse
// Contest: Codeforces - Educational Codeforces Round 160 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1913/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second
#define endl '\n'
#define int long long
const LL maxn = 4e05+7;
const LL N = 5e05+10;
const LL mod = 998244353;
const int inf = 0x3f3f3f3f;
const LL llinf = 5e18;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >mi;//小根堆
priority_queue<LL> ma;//大根堆
LL gcd(LL a, LL b){
return b > 0 ? gcd(b , a % b) : a;
}
LL lcm(LL a , LL b){
return a / gcd(a , b) * b;
}
int n , m;
vector<int>a(N , 0);
void init(int n){
for(int i = 0 ; i <= n ; i ++){
a[i] = 0;
}
}
void solve()
{
int n;
cin >> n;
vector<int>dp(n + 5 , 0);
vector<int>sum(n + 5 , 0);
vector<int>dp2(n + 5 , 0);
for(int i = 1 ; i <= n ; i ++)
cin >> a[i];
stack<pair<int,int>>st;
vector<int>tl(n + 5 , 0);
for(int i = 1 ; i <= n ; i ++){
while(!st.empty()){
auto tmp = st.top();
if(a[i] < tmp.x){
st.pop();
}
else{
break;
}
}
if(st.empty()){
st.push({a[i] , i});
tl[i] = 0;
}
else{
auto tmp = st.top();
tl[i] = tmp.y;
st.push({a[i] , i});
}
}
for(int i = 1 ; i <= n ; i ++){
dp[i] = sum[i - 1] - sum[tl[i]];
dp[i] += mod;
if(tl[i] == 0){
dp[i]++;
}
dp[i] += dp2[tl[i]];
sum[i] = sum[i - 1] + dp[i];
dp2[i] = dp2[tl[i]] + dp[i];
dp[i] %= mod;
sum[i] %= mod;
dp2[i] %= mod;
}
int ans = 0;
while(!st.empty()){
st.pop();
}
for(int i = n ; i >= 1 ; i --){
while(!st.empty()){
auto tmp = st.top();
if(a[i] < tmp.x){
st.pop();
}
else{
break;
}
}
if(st.empty()){
ans += dp[i];
ans %= mod;
st.push({a[i] , i});
}
else{
st.push({a[i] , i});
}
}
cout << ans << endl;
//10
//10 2
///10 2 6 10 6
//
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
cin>>t;
while(t--)
{
solve();
}
return 0;
}
文章来源:https://blog.csdn.net/weixin_61825750/article/details/135082175
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!