传送门:Codeforces Round #353 (Div. 2) E. Trains and Statistic
题意:
有n个车站,(n<=1e5),每个车站都有一个a[i],意味着从该车站可以花费1的时间
到达[i+1,a[i]]之间的任意车站 , 求d[i][j]的和的最小值(1<=i<=n,i+1<=j<=n)
思路:
dp[i]表示从i点出发到i+1,i+2,...,n的最小值,
那么如果j<=a[i]的话,就+=1,否则就贪心找到[i+1,a[i]]里面a[i]
最大的那个车站,转移到这个车站去 , dp[i][j]=dp[num][j]+1,这样贪心肯定是最小的但是贪心的正确性怎么证明呢?
我们考虑i到j的花费的最小值,如果j<=a[i],那么花费肯定是1 , 如果大于a[i],dp[i][j]=1+dp[num][j],因为num这个点的a[i]是最大的,
所以在num这个点可以走到的最远点是最远的,所以一步一步贪心,花费肯定是最少的。
#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
typedef long long LL;
const int maxn=100100;
typedef pair<int,int> PI;
int minv[4*maxn],id[4*maxn],a[maxn];
LL dp[maxn];
void pushup(int rt){
if(minv[rt<<1]>=minv[rt<<1|1])
minv[rt]=minv[rt<<1],id[rt]=id[rt<<1];
else
minv[rt]=minv[rt<<1|1],id[rt]=id[rt<<1|1];
}
void build(int l,int r,int rt){
if(l==r){
minv[rt]=a[l];
id[rt]=l;
return ;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
pushup(rt);
}
int L,R;
PI query(int l,int r,int rt){
if(L<=l&&R>=r)
return make_pair(minv[rt],id[rt]);
int mid=(l+r)>>1;
PI ans1={0,0},ans2={0,0};
if(L<=mid)
ans1=query(lson);
if(R>mid)
ans2=query(rson);
if(ans1.first<ans2.first)
return ans2;
return ans1;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<n;i++)
scanf("%d",&a[i]);
a[n]=INT_MAX;
build(1,n,1);
dp[n]=0;
LL ans=0;
L=3,R=10;
query(1,n,1);
for(int i=n-1;i>=1;i--){
L=i+1,R=a[i];
int num=query(1,n,1).second;
dp[i]=dp[num]+(n-i)-(a[i]-num);
ans+=dp[i];
}
printf("%lld\n",ans);
}