【codeforces 675E】【DP+线段树维护】【给出n个车站,并告诉你第i个车站有从i+1到a[i]个车站的直达票,问你所有车站到其余各个车站的最小车票花费和】
2016-10-02 22:52
567 查看
传送门:E. Trains and Statistic
描述:
E. Trains and Statistic
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Vasya commutes by train every day. There are n train stations in the city, and at the i-th
station it's possible to buy only tickets to stations from i + 1 to ai inclusive.
No tickets are sold at the last station.
Let ρi, j be
the minimum number of tickets one needs to buy in order to get from stations i to station j.
As Vasya is fond of different useless statistic he asks you to compute the sum of all values ρi, j among
all pairs 1 ≤ i < j ≤ n.
Input
The first line of the input contains a single integer n (2 ≤ n ≤ 100 000) —
the number of stations.
The second line contains n - 1 integer ai (i + 1 ≤ ai ≤ n),
the i-th of them means that at the i-th
station one may buy tickets to each station from i + 1 to ai inclusive.
Output
Print the sum of ρi, j among
all pairs of 1 ≤ i < j ≤ n.
Examples
input
output
input
output
Note
In the first sample it's possible to get from any station to any other (with greater index) using only one ticket. The total number of pairs is 6,
so the answer is also 6.
Consider the second sample:
ρ1, 2 = 1
ρ1, 3 = 2
ρ1, 4 = 3
ρ1, 5 = 3
ρ2, 3 = 1
ρ2, 4 = 2
ρ2, 5 = 2
ρ3, 4 = 1
ρ3, 5 = 1
ρ4, 5 = 1
Thus the answer equals 1 + 2 + 3 + 3 + 1 + 2 + 2 + 1 + 1 + 1 = 17.
题意:
给出n个车站,并告诉你第i个车站有从i+1到a[i]个车站的直达票,问你所有车站到其余各个车站的最小车票花费和。
思路:
我们用dp[i]表示第i个车站从i+1到n最小车票花费总和。那么dp
=0,于是就可以从n到1逆推,求和计算出答案。
我们再来看如何得到dp[i]。对于从i+1到a[i]的车站,从第i号车站各只需要一张车票即可。但是对于大于a[i]的车站,我们可以找到从i+1到a[i]的a值最大的车站m。因为a[m]最大,所以能到达的范围也就更大,所以从这个m车站到剩下的车站花费车票一定最少的。这也就是我们贪心的依据。
找这个m的时候可以先用线段树求出区间里最大的a值然后用set二分查询一下m
这时候我们发现从m+1到a[i]在dp[m]中已经计算过了,各多算了一次,所以结果要减去a[i]-m,
算得dp[i]=dp[m]+(n-i)-(a[i]-m),
再将所有的dp[i]加起来就好了
线段树专题参考Here
代码:
#include <bits/stdc++.h>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define pr(x) cout << #x << "= " << x << " " ;
#define pl(x) cout << #x << "= " << x << endl;
#define ll __int64
using namespace std;
#define mst(ss,b) memset(ss,b,sizeof(ss));
#define For(i,j,n) for(int i=j;i<=n;i++)
template<class T> void read(T&num) {
char CH; bool F=false;
for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p) {
if(!p) { puts("0"); return; }
while(p) stk[++ tp] = p%10, p/=10;
while(tp) putchar(stk[tp--] + '0');
putchar('\n');
}
const int N=1e5+10;
ll dp
,ans=0;
int Max[N<<2],a
,n;
set<int>s
;
void PushUp(int rt){
Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}
void build(int l,int r,int rt){//线段树求区间最大值
if(l==r){
Max[rt]=a[l];
return;
}
int m=(r+l)>>1;
build(lson);
build(rson);
PushUp(rt);
}
int query(int L,int R, int l,int r,int rt){
if(L<=l && r<=R)return Max[rt];
int m=(l+r)>>1;
int ret=0;
if(L<=m)ret=max(ret, query(L, R, lson));
if(R>m)ret=max(ret,query(L, R, rson));
return ret;
}
int main(){
read(n);
s[0].insert(n);
for(int i=1; i<n; i++){
read(a[i]);
s[a[i]].insert(i);
}
build(1, n, 1);
dp
=0;
for(int i=n-1; i>=1; i--){
int m=query(i+1, a[i], 1, n, 1);//求i+1——a[i]车站之间某车站m使得a[m]最大
m=*s[m].lower_bound(i+1);//返回大于等于i+1中第一个出现a[m]的下标
dp[i]=dp[m]+n-i-(a[i]-m);
ans+=dp[i];
}
print(ans);
return 0;
}
描述:
E. Trains and Statistic
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Vasya commutes by train every day. There are n train stations in the city, and at the i-th
station it's possible to buy only tickets to stations from i + 1 to ai inclusive.
No tickets are sold at the last station.
Let ρi, j be
the minimum number of tickets one needs to buy in order to get from stations i to station j.
As Vasya is fond of different useless statistic he asks you to compute the sum of all values ρi, j among
all pairs 1 ≤ i < j ≤ n.
Input
The first line of the input contains a single integer n (2 ≤ n ≤ 100 000) —
the number of stations.
The second line contains n - 1 integer ai (i + 1 ≤ ai ≤ n),
the i-th of them means that at the i-th
station one may buy tickets to each station from i + 1 to ai inclusive.
Output
Print the sum of ρi, j among
all pairs of 1 ≤ i < j ≤ n.
Examples
input
4 4 4 4
output
6
input
5 2 3 5 5
output
17
Note
In the first sample it's possible to get from any station to any other (with greater index) using only one ticket. The total number of pairs is 6,
so the answer is also 6.
Consider the second sample:
ρ1, 2 = 1
ρ1, 3 = 2
ρ1, 4 = 3
ρ1, 5 = 3
ρ2, 3 = 1
ρ2, 4 = 2
ρ2, 5 = 2
ρ3, 4 = 1
ρ3, 5 = 1
ρ4, 5 = 1
Thus the answer equals 1 + 2 + 3 + 3 + 1 + 2 + 2 + 1 + 1 + 1 = 17.
题意:
给出n个车站,并告诉你第i个车站有从i+1到a[i]个车站的直达票,问你所有车站到其余各个车站的最小车票花费和。
思路:
我们用dp[i]表示第i个车站从i+1到n最小车票花费总和。那么dp
=0,于是就可以从n到1逆推,求和计算出答案。
我们再来看如何得到dp[i]。对于从i+1到a[i]的车站,从第i号车站各只需要一张车票即可。但是对于大于a[i]的车站,我们可以找到从i+1到a[i]的a值最大的车站m。因为a[m]最大,所以能到达的范围也就更大,所以从这个m车站到剩下的车站花费车票一定最少的。这也就是我们贪心的依据。
找这个m的时候可以先用线段树求出区间里最大的a值然后用set二分查询一下m
这时候我们发现从m+1到a[i]在dp[m]中已经计算过了,各多算了一次,所以结果要减去a[i]-m,
算得dp[i]=dp[m]+(n-i)-(a[i]-m),
再将所有的dp[i]加起来就好了
线段树专题参考Here
代码:
#include <bits/stdc++.h>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define pr(x) cout << #x << "= " << x << " " ;
#define pl(x) cout << #x << "= " << x << endl;
#define ll __int64
using namespace std;
#define mst(ss,b) memset(ss,b,sizeof(ss));
#define For(i,j,n) for(int i=j;i<=n;i++)
template<class T> void read(T&num) {
char CH; bool F=false;
for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p) {
if(!p) { puts("0"); return; }
while(p) stk[++ tp] = p%10, p/=10;
while(tp) putchar(stk[tp--] + '0');
putchar('\n');
}
const int N=1e5+10;
ll dp
,ans=0;
int Max[N<<2],a
,n;
set<int>s
;
void PushUp(int rt){
Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}
void build(int l,int r,int rt){//线段树求区间最大值
if(l==r){
Max[rt]=a[l];
return;
}
int m=(r+l)>>1;
build(lson);
build(rson);
PushUp(rt);
}
int query(int L,int R, int l,int r,int rt){
if(L<=l && r<=R)return Max[rt];
int m=(l+r)>>1;
int ret=0;
if(L<=m)ret=max(ret, query(L, R, lson));
if(R>m)ret=max(ret,query(L, R, rson));
return ret;
}
int main(){
read(n);
s[0].insert(n);
for(int i=1; i<n; i++){
read(a[i]);
s[a[i]].insert(i);
}
build(1, n, 1);
dp
=0;
for(int i=n-1; i>=1; i--){
int m=query(i+1, a[i], 1, n, 1);//求i+1——a[i]车站之间某车站m使得a[m]最大
m=*s[m].lower_bound(i+1);//返回大于等于i+1中第一个出现a[m]的下标
dp[i]=dp[m]+n-i-(a[i]-m);
ans+=dp[i];
}
print(ans);
return 0;
}
相关文章推荐
- hdu 2295 Radar 重复覆盖 DLX+二分答案 给出一些城市及一些雷达的坐标,要求从这些雷达中选取最多k个能够覆盖所有的城市,问雷达的最小覆盖半径为多少
- 【codeforces 721D】【贪心 堆】D. Maxim and Array 【给出n个数,k次机会,每次使得任意一个数字减少或者加上x,使得最后的乘积最小,最后的n个数大小】
- 把一个包含n个正整数的序列划分成m个连续的子序列。设第i个序列的各数之和为S(i),求所有S(i)的最大值的最小值是多少?
- hdoj 3072 Intelligence System【求scc&&缩点】【求连通所有scc的最小花费】
- 给出N个正整数,其中只有一个数出现了奇数次,其余的数都出现偶数次。求那个出现了奇数次的数。1<=N<=1000,N肯定是奇数。所有出现的整数都不超过1000。
- FindKth(T,i)返回树T的具有第i个最小关键字的元素。所有元素具有关键字互异的关键字。修改二叉树以平均O(logN)时间支持这种运算
- 一条长l的笔直的街道上有n个路灯,若这条街的起点为0,终点为l,第i个路灯坐标为ai,每盏灯可以覆盖到的最远距离为d,为了照明需求,所有灯的灯光必须覆盖整条街,但是为了省电,要是这个d最小,请找到这个最小的d。
- hdu 4003 求用k个机器人遍历一棵树的所有节点所需的最小花费
- [LCT维护最小生成树 || CDQ分治 || 线段树 并查集 dfs树] Codeforces 603E #334 (Div. 1) E. Pastoral Oddities
- 给出形如2012-02-01和2012-04-04这样的两个string,如何用java获得这个时间段内的所有日期
- 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
- Codeforces 311E. Biologist (最小割)
- 给出一个函数来输出一个字符串的所有排列。
- 1.编写一个简单的C语言程序:根据输入的两个整数求平均值并且在终端输出,通过gcc编译器得到它的汇编程序文件。 2.编写一个C语言程序:打印输出所有“水仙花数”,用gdb调试程序(给出步骤)。所谓“
- poj 2186 Popular Cows【tarjan求scc个数&&缩点】【求一个图中可以到达其余所有任意点的点的个数】
- 提出支持栈的Push和Pop操作以及第三种操作FindMin的数据结构,其中FindMin返回该数据结构的最小元素 所有操作在最坏的情况下的运行时间都是O(1)
- 跳槽3次才算弄明白的4个秘密,所有公司都不会告诉你(收集互联网)
- 求数组中除第i个外的所有其他数组元素的乘积
- Codeforces 588E Duff in the Army 【树链剖分维护区间前k小】
- 【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集