CF-675-E-RMQ优化DP

675-E 题目大意

n个车站,以及一个长度为n的序列a1,a2······an,第i个车站可以直接到达[i+1,ai]中的任意一个车站。记p[i][j]为从车站i到车站j的最小步数,求:

i=1nj=i+1np[i][j]


Solution

dp[i]为从车站i到后面车站的最小步数和,正着考虑一个车站可能对应着多个后面的车站的状态,不妨倒着考虑,车站i的状态能够从后面哪个车站转移而来。

基于贪心,我们应当从区间[i+1,ai]中选出一个下一步能够走得最远的车站j,即max(a[j]),j[i+1,ai]。这时转移方程为:

dp[i]=dp[j]+ji+(na[i])

这里转移是怎么来的,分两部分考虑,一部分在[i+1,ai]中,这里面的车站i可以一步到达,这里的贡献为ji+(dp[j]的一部分),另一部分则是在[ai+1,n]中,这里面的车站需要i先转移到j再转移过去,换句话说就是在车站j到这些车站最小步数的基础上还需要多走一步,这一部分的贡献为na[i]+(dp[j]的另一部分)

转移方程找到之后,剩下的问题就是在一段区间[l,r]中找到最大值a[j],这部分就是RMQ问题了,用ST表、树状数组、线段树均可,时间复杂度O(nlogn)

#include<bits/stdc++.h>
using namespace std;
using ll=long long;

template<typename T>
struct Fenwick{
	int n;
	vector<T> tr;
	Fenwick(int _n):tr(_n+1),n(_n){
		for(int i=0;i<=n;i++) tr[i]={0,0};
	}
	int lowbit(int x){
		return x&-x;
	}
	void add(int u,T x){
		for(int i=u;i<=n;i+=lowbit(i)) if(x.first>=tr[i].first) tr[i]=x;
	}
	T query(int u){
		T res={0,0};
		for(int i=u;i;i-=lowbit(i)) if(tr[i].first>=res.first) res=tr[i];
		return res;
	}
};

int main(){
    int n;
    cin>>n;
    vector<int> a(n+1);
    for(int i=1;i<n;i++){
        cin>>a[i];
        a[n]=n;
    }
    vector<vector<pair<int,int>>> e(n);
    ll ans=0;
    Fenwick<pair<int,int>> fen(n*2);
    fen.add(n,{n,n});
    vector<ll> dp(n+1);
    for(int i=n-1;i;i--){
        auto p=fen.query(a[i]);
        dp[i]=dp[p.second]+p.second-i+n-a[i];
        ans+=dp[i];
        fen.add(i,{a[i],i});
    }
    cout<<ans<<'\n';
    return 0;
}
posted @   fengxue-K  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示