CodeForces

来源:互联网 发布:mysql 进入数据库 编辑:程序博客网 时间:2024/06/05 03:30

题意:一开始 你在第一个站 现在告诉每个站可以买一张票去其他地方(只能去比他坐标大的) 最后一个站没有卖


n表示 有n张车站


于是有n-1张车票


车票ai 表示这张车票可以从 i 车站出发 去 i+1 车站到 ai车站的任意一个车站 


现在 假设 pij 表示从i 到 j 的车站 最小用票数量


求所有的pij的和


思路:


假设我们在i车站 可以到  a b c 三个车站 而a b c必然可以到达其他的所有车站 (a < b <c )


其中 如果通过 a b c 再去其他站   我们选择肯定是a b c 中 能去最远的那个作为第二站


那么 假设b能去最远 我们通过 b 到达其他后面所有车站  且c是i一张票最远能去的车站 (b能去最远的距离必然大于c)


如果 我们通过一个车站 到达其他后面所有车站 那么相当于要每次多花一张票 除了 一张票就能到达的地方


那么 就需要 n-i + 中间站到其他所有站的票数 - c-b


故此就可以求出答案

#include <iostream>#include <stdio.h>using namespace std;#define MAX 100010#define LL long longLL ans;int dp[MAX*4];LL a[MAX];int rr[MAX];int q,u;void build(int l,int r,int tt){    if(l==r)    {        dp[tt]=rr[l];        return ;    }    int mid=(l+r)/2;    build(mid+1,r,tt*2+1);    build(l,mid,tt*2);    dp[tt]=max(dp[tt*2],dp[tt*2+1]);}void query(int l,int r,int tt,int x,int y){    if(x==l&&y==r)    {        if(dp[tt]>q)        {            q=dp[tt];            while(l!=r)            {                int mid=(l+r)/2;                if(dp[tt*2]==q){ r=mid;tt=tt*2;}                else {l=mid+1; tt=tt*2+1;}            }            u=l;        }        return ;    }    int mid=(l+r)/2;    if(mid<x)        query(mid+1,r,tt*2+1,x,y);    else if(y<=mid)        query(l,mid,tt*2,x,y);    else    {        query(l,mid,tt*2,x,mid);        query(mid+1,r,tt*2+1,mid+1,y);    }}int main(){    int n;    scanf("%d",&n);    for(int i=1;i<n;i++)    {        scanf("%d",&rr[i]);    }    rr[n]=n;    build(1,n,1);    for(int i=n-1;i>=1;i--)    {        q=0;        query(1,n,1,i+1,rr[i]);        a[i]=n-i+a[u]-(rr[i]-u);        ans+=a[i];    }    printf("%lld\n",ans);    return 0;}



原创粉丝点击