习题:Trains and Statistic(DP)
题目
思路
我们考虑一种贪心策略
如果从u不能一步到达v,那么一定存在一种方案使得u的第一步是达到\(u+1到p_u\)中最大的一个\(p_i\)的i位置
也就是指我们可以考虑从后往前扫,\(dp_i\)表示以i号节点为起始节点的总和
之后考虑i号节点到其他节点都是要多走一步,但是对于\(j到a_i\)的位置却夺走了一步,所以还要减去
\(dp_i=dp_j+(n-i)+(a_i-j)\)
区间最大值直接线段树不香?
虽然可以直接用st表
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
#define pii pair<int,int>
#define x first
#define y second
namespace lst
{
long long a[100005];
struct node
{
int l,r;
int val,ans;
}tre[400005];
void build(int l,int r,int k)
{
tre[k].l=l;
tre[k].r=r;
if(l==r)
{
tre[k].val=a[l];
tre[k].ans=l;
return;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
if(tre[k<<1].val>tre[k<<1|1].val)
tre[k].ans=tre[k<<1].ans;
else
tre[k].ans=tre[k<<1|1].ans;
tre[k].val=max(tre[k<<1].val,tre[k<<1|1].val);
}
pii ask(int l,int r,int k)
{
if(l>tre[k].r||tre[k].l>r)
return make_pair(0,0);
if(l<=tre[k].l&&tre[k].r<=r)
return make_pair(tre[k].ans,tre[k].val);
pii t1=ask(l,r,k<<1),t2=ask(l,r,k<<1|1);
if(t1.y>t2.y)
return t1;
else
return t2;
}
}
using namespace lst;
int n;
long long ans;
long long dp[100005];
int main()
{
cin>>n;
for(int i=1;i<n;i++)
cin>>a[i];
build(1,n-1,1);
dp[n]=0;
for(int i=n-1;i>=1;i--)
{
if(a[i]>=n)
dp[i]=n-i;
else
{
pii t1=ask(i+1,a[i],1);
//printf("When i == %d, k == %d\n",i,t1.x);
dp[i]=dp[t1.x]+(n-i)-(a[i]-t1.x);
}
//printf("f[%d] == %lld\n",i,dp[i]);
ans=ans+dp[i];
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号