NOIP 2011 Senior 2 - 选择客栈
2017-07-05 15:35
447 查看
选择客栈
总时间限制: 1000ms 内存限制: 65535kB
描述
丽江河边有 n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号。每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示) ,且每家客栈都设有一家咖啡店,每家咖啡店均有各自的最低消费。
两位游客一起去丽江旅游,他们喜欢相同的色调,又想尝试两个不同的客栈,因此决定分别住在色调相同的两家客栈中。晚上,他们打算选择一家咖啡店喝咖啡,要求咖啡店位于两人住的两家客栈之间(包括他们住的客栈) ,且咖啡店的最低消费不超过 p。
他们想知道总共有多少种选择住宿的方案,保证晚上可以找到一家最低消费不超过 p 元的咖啡店小聚。
输入
第一行三个整数 n,k,p,每两个整数之间用一个空格隔开,分别表示客栈的个数,色调的数目和能接受的最低消费的最高值;
接下来的 n行,第 i+1 行两个整数,之间用一个空格隔开,分别表示 i 号客栈的装饰色调和 i 号客栈的咖啡店的最低消费。
输出
输出只有一行,一个整数,表示可选的住宿方案的总数。
样例输入
5 2 3
0 5
1 3
0 2
1 4
1 5
样例输出
3
提示
2 人要住同样色调的客栈,所有可选的住宿方案包括:住客栈①③,②④,②⑤,④⑤,
但是若选择住 4、5 号客栈的话,4、5 号客栈之间的咖啡店的最低消费是 4,而两人能承受的最低消费是 3 元,所以不满足要求。因此只有前 3 种方案可选。
数据范围
对于 30%的数据,有 n ≤ 100;
对于 50%的数据,有 n ≤ 1,000;
对于 100%的数据,有 2 ≤ n≤ 200,000,0 < k ≤ 50,0 ≤ p ≤ 100, 0 ≤ 最低消费 ≤ 100。
思路 1
不管怎么说,第一个思路还是枚举。直接枚举选择的客栈,时间复杂度为O(n^2)。但是每次获取一个区间的最小值的时间复杂度为O(n),所以整个算法的时间复杂度为O(n^3)。
预计得分:30
思路 2
既然要取最小值,就想到了RMQ算法,初始化的时间复杂度为O(n log n),整个算法的时间复杂度为O(n^2)。
预计得分:50
思路 3
根据普及组的经验,可以将客栈色调的总数k运用起来,将所有同一色调的客栈分成一组。这样的时间复杂度虽然仍是O(n^2),但是可能会多过一两个点。
思路 4
受思路三的启发,可以用相同的思路提取一些公式。
假设某一种色调的客栈为A0,A1, …, An(这里的n指这种色调的客栈的总数)。
可以发现,若客栈Ax
4000
,Ax+1之间的最小值小于等于p,那么以这两个客栈为分界线,左边右边任选一个(包括Ax,Ax+1),是都能满足条件的,这样的方案总数为x*(i-x)。如果我们枚举每一个客栈之间的间隔,那么总的时间复杂度可以为O(n),在使用RMQ后为O(n log n),200000的数据应该能过了。
接下来考虑细节。因为有可能重复计算,所以我们可以考虑以下情况:
A1 A2 A3 A4 A5
满↑足 满↑足
在A1,A2之间满足条件,则可以有1∗4种方案。在A3,A4之间也满足条件,单独计算的话有3*2种方案,但是A1在左边的情况已经计算过了,所以我们可以保存上次计算的位置,然后减去重复的就可以了。对这个例子而言,先计算A1∗(A2−A5),然后计算 (A2−A3)∗(A4−A5),不计算A1∗(A4−A5)的重复情况。
得分:100
思路 5 动态维护O(1)数据
从1到n枚举所有的客栈i,然后计算从1到客栈i-1中有符合条件的客栈的个数,其和便是答案。这种思想正是枚举的思想,但是如果能把这种思想中的某些步骤做到时间复杂度为O(1),那么问题就解决了。往往这么做的效率很高,因此这种思路是一种非常重要的思路,而实现这种思路也是一种非常重要的能力。
首先,让我们考虑一下咖啡店的选址。毫无疑问,以我们刚刚的思路来做的话咖啡店是越往右越好的。这一点很好维护,只需要用一个bestPos变量来更新就可以了。
然后,我们可以考虑如何计算1到i-1号客栈中符合条件的客栈。由于要求颜色相同,因此我们可以用一个数组来保存计算到第i号时各个色调的客栈的个数。
然而,我们需要的是1到i-1号中符合条件的,所以得想办法维护它。我们注意到,每当bestPos更新时,都可以保证在bestPos之前的所有同色客栈可用……这样推算下去,我们一共需要4个辅助数据就能实现O(1)查询(自己想确实不怎么好想,但是看代码应该很好理解):
最后计算答案的部分:
惊讶的发现,这种算法不仅时间复杂度是绝对的O(n),而且空间复杂度也和n无关,只与k有关。因此,这种动态维护O(1)数据的方法的威力不容小觑。
总时间限制: 1000ms 内存限制: 65535kB
描述
丽江河边有 n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号。每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示) ,且每家客栈都设有一家咖啡店,每家咖啡店均有各自的最低消费。
两位游客一起去丽江旅游,他们喜欢相同的色调,又想尝试两个不同的客栈,因此决定分别住在色调相同的两家客栈中。晚上,他们打算选择一家咖啡店喝咖啡,要求咖啡店位于两人住的两家客栈之间(包括他们住的客栈) ,且咖啡店的最低消费不超过 p。
他们想知道总共有多少种选择住宿的方案,保证晚上可以找到一家最低消费不超过 p 元的咖啡店小聚。
输入
第一行三个整数 n,k,p,每两个整数之间用一个空格隔开,分别表示客栈的个数,色调的数目和能接受的最低消费的最高值;
接下来的 n行,第 i+1 行两个整数,之间用一个空格隔开,分别表示 i 号客栈的装饰色调和 i 号客栈的咖啡店的最低消费。
输出
输出只有一行,一个整数,表示可选的住宿方案的总数。
样例输入
5 2 3
0 5
1 3
0 2
1 4
1 5
样例输出
3
提示
2 人要住同样色调的客栈,所有可选的住宿方案包括:住客栈①③,②④,②⑤,④⑤,
但是若选择住 4、5 号客栈的话,4、5 号客栈之间的咖啡店的最低消费是 4,而两人能承受的最低消费是 3 元,所以不满足要求。因此只有前 3 种方案可选。
数据范围
对于 30%的数据,有 n ≤ 100;
对于 50%的数据,有 n ≤ 1,000;
对于 100%的数据,有 2 ≤ n≤ 200,000,0 < k ≤ 50,0 ≤ p ≤ 100, 0 ≤ 最低消费 ≤ 100。
思路 1
不管怎么说,第一个思路还是枚举。直接枚举选择的客栈,时间复杂度为O(n^2)。但是每次获取一个区间的最小值的时间复杂度为O(n),所以整个算法的时间复杂度为O(n^3)。
预计得分:30
思路 2
既然要取最小值,就想到了RMQ算法,初始化的时间复杂度为O(n log n),整个算法的时间复杂度为O(n^2)。
预计得分:50
思路 3
根据普及组的经验,可以将客栈色调的总数k运用起来,将所有同一色调的客栈分成一组。这样的时间复杂度虽然仍是O(n^2),但是可能会多过一两个点。
思路 4
受思路三的启发,可以用相同的思路提取一些公式。
假设某一种色调的客栈为A0,A1, …, An(这里的n指这种色调的客栈的总数)。
可以发现,若客栈Ax
4000
,Ax+1之间的最小值小于等于p,那么以这两个客栈为分界线,左边右边任选一个(包括Ax,Ax+1),是都能满足条件的,这样的方案总数为x*(i-x)。如果我们枚举每一个客栈之间的间隔,那么总的时间复杂度可以为O(n),在使用RMQ后为O(n log n),200000的数据应该能过了。
接下来考虑细节。因为有可能重复计算,所以我们可以考虑以下情况:
A1 A2 A3 A4 A5
满↑足 满↑足
在A1,A2之间满足条件,则可以有1∗4种方案。在A3,A4之间也满足条件,单独计算的话有3*2种方案,但是A1在左边的情况已经计算过了,所以我们可以保存上次计算的位置,然后减去重复的就可以了。对这个例子而言,先计算A1∗(A2−A5),然后计算 (A2−A3)∗(A4−A5),不计算A1∗(A4−A5)的重复情况。
long long ans = 0; for (int i = 0; i < k; i++) { int size = styleSet[i].size(); //当前色调客栈个数 int right = size - 1; int lastLeft = 0; //用于记录上一次计算了的位置以去掉重复计算 for (int j = 0; j < size - 1; j++) { if (rmq.query(styleSet[i][j], styleSet[i][j + 1]) <= p) //如果这两个客栈之间满足最小花费小于p { ans += (j - lastLeft + 1) * (right - j); //去重 lastLeft = j + 1; //记录 } } } cout << ans;
得分:100
思路 5 动态维护O(1)数据
从1到n枚举所有的客栈i,然后计算从1到客栈i-1中有符合条件的客栈的个数,其和便是答案。这种思想正是枚举的思想,但是如果能把这种思想中的某些步骤做到时间复杂度为O(1),那么问题就解决了。往往这么做的效率很高,因此这种思路是一种非常重要的思路,而实现这种思路也是一种非常重要的能力。
首先,让我们考虑一下咖啡店的选址。毫无疑问,以我们刚刚的思路来做的话咖啡店是越往右越好的。这一点很好维护,只需要用一个bestPos变量来更新就可以了。
然后,我们可以考虑如何计算1到i-1号客栈中符合条件的客栈。由于要求颜色相同,因此我们可以用一个数组来保存计算到第i号时各个色调的客栈的个数。
然而,我们需要的是1到i-1号中符合条件的,所以得想办法维护它。我们注意到,每当bestPos更新时,都可以保证在bestPos之前的所有同色客栈可用……这样推算下去,我们一共需要4个辅助数据就能实现O(1)查询(自己想确实不怎么好想,但是看代码应该很好理解):
int bestPos = 0; //咖啡店应尽量靠右,保存咖啡店的最佳地址 int times[maxn] = { 0 }; //保存同色客栈出现的次数 int lastAppear[maxn] = { 0 }; //保存某种颜色客栈上一次出现的位置 int availableTimes[maxn] = { 0 }; //保存某种颜色客栈可形成一对的个数
最后计算答案的部分:
long long ans = 0; for (int i = 1; i <= n; i++) { int style = readIn(); int cost = readIn(); if (cost <= p) { bestPos = i; //维护咖啡店位置 } if (bestPos >= lastAppear[style]) //若bestPos在上一次这个颜色的客栈还要后面一点,就可以保证有times[style]个客栈可配对(此时times还没有更新) availableTimes[style] = times[style]; lastAppear[style] = i; //维护上一次出现的位置 times[style]++; //维护出现的次数 ans += availableTimes[style]; //计算答案 }
惊讶的发现,这种算法不仅时间复杂度是绝对的O(n),而且空间复杂度也和n无关,只与k有关。因此,这种动态维护O(1)数据的方法的威力不容小觑。
相关文章推荐
- NOIP2011 day1 选择客栈
- [Noip2011] 选择客栈
- 【NOIP2011】选择客栈 乱搞
- NOIP 2011 选择客栈
- 【noip2011】【codevs1135】选择客栈
- 【NOIP2011】选择客栈
- [NOIP 2011]选择客栈 模拟
- JZOJ【NOIP2011DAY1】选择客栈(hotel)
- 选择客栈 NOIP2011 提高组 Day1 T2
- 【noip 2011】选择客栈
- luogu1311 选择客栈(NOIP2011提高组第2题)
- [1st.Aug.16.] NOIP2011 选择客栈——最终其实没有做出来
- [Wikioi 1135][NOIP 2011提高组]选择客栈
- NOIP2011提高组(选择客栈)
- NOIP 2011 DAY 1 解题报告(铺地毯,选择客栈,mayan游戏)
- noip2011选择客栈o(n)
- 口胡【NOIP2011DAY1】选择客栈
- 【枚举优化】【NOIP2011提高组】选择客栈 hotel
- 洛谷 P1311 [NOIP2011 D1T1] 选择客栈
- NOIP2011 选择客栈 题解(最简方法,超短代码)