#rMQybttg040206. 1546:NOIP2011 选择客栈
1546:NOIP2011 选择客栈
好的,我将这道题整理为清晰的题面格式,并补充样例解释、数据范围与时空限制:
题目描述
丽江河边有 家很有特色的客栈,客栈按照其位置顺序从 到 编号。
每家客栈都按照某一种色调进行装饰(总共 种,用整数 表示),且每家客栈都设有一家咖啡店,每家咖啡店均有各自的最低消费。
两位游客一起去丽江旅游,他们喜欢相同的色调,又想尝试两个不同的客栈,因此决定分别住在色调相同的两家客栈中。
晚上,他们打算选择一家咖啡店喝咖啡,要求咖啡店位于两人住的两家客栈之间(包括他们住的客栈),且咖啡店的最低消费不超过 。
他们想知道总共有多少种选择住宿的方案,保证晚上可以找到一家最低消费不超过 元的咖啡店小聚。
输入格式
第一行三个整数 ,每两个整数之间用一个空格隔开,分别表示客栈的个数,色调的数目和能接受的最低消费的最高值;
接下来的 行,第 行两个整数,之间用一个空格隔开,分别表示 号客栈的装饰色调 和 号客栈的咖啡店的最低消费 。
输出格式
输出一行,一个整数,表示可选的住宿方案的总数。
样例
样例输入
5 2 3
0 5
1 3
0 2
1 4
1 5
样例输出
3
样例说明
客栈编号:1 2 3 4 5
色调:0 1 0 1 1
最低消费:5 3 2 4 5
要求两人住相同色调的客栈,且中间(含两端)有至少一家咖啡店最低消费 。
可能方案:
- (1,3):色调 0,中间咖啡店有 1(5),2(3),3(2),最低消费有 3,2 ≤ 3,可行;
- (2,4):色调 1,中间咖啡店有 2(3),3(2),4(4),最低消费有 3,2 ≤ 3,可行;
- (2,5):色调 1,中间咖啡店有 2(3),3(2),4(4),5(5),最低消费有 3,2 ≤ 3,可行;
- (4,5):色调 1,中间咖啡店有 4(4),5(5),最低消费都 >3,不可行。
所以可行方案数为 。
数据范围
- 对于 的数据,有 ;
- 对于 的数据,有 ;
- 对于 的数据,有 ;
- 对于 的数据,有 $2 \le n \le 2\times 10^6,0<k<10^4,0 \le p \le 100,0 \le b_i \le 100$。
时空限制
- 时间:
- 内存:(512 MB)
提示
此题可以 或 解决,由于 可达 , 可达 ,需要线性或接近线性的算法。
思路:
- 从左到右扫描,维护对于每种颜色,最近一次出现“可行咖啡店”的位置;
- 对于当前客栈 ,如果 ,则它是一个“可行咖啡店”;
- 对于当前客栈 ,色调为 ,我们需要知道之前色调为 的客栈中,有多少个可以与之配对,使得它们之间有可行咖啡店。
具体做法:
- 设 表示色调 的客栈最近一次出现的位置;
- 设 表示最近一个可行咖啡店的位置(即 的最大 );
- 设 表示色调 的客栈中,最近一个可行咖啡店之后(含)的客栈数量。
扫描过程:
- 若当前 ,则更新 ;
- 对于色调 :
- 如果 (即最近的同色客栈在最近可行咖啡店之前或相同位置),则当前客栈 可以和之前所有色调 的客栈配对(共 个);
- 否则,当前客栈 只能和最近可行咖啡店之后(含)的色调 的客栈配对(即 个);
- 然后将 加上 ;
- 更新 (当前客栈加入计数);
- 更新 。
解释:
实际上记录了最近一个可行咖啡店之后(含)的色调 的客栈数量。
当出现新的可行咖啡店时, 更新,但 不会清零,因为之前的客栈仍然可以和之后的客栈配对(只要可行咖啡店在它们之间)。
注意:
- 初始化 ;
- ;
- 答案可能很大,用
long long存储。
复杂度:。
样例运行(按上述算法):
- i=1: c=0, b=5>3, pos=0, last[0]=0, sum[0]=0, 加 0, sum[0]=1, last[0]=1
- i=2: c=1, b=3≤3, pos=2, last[1]=0, sum[1]=0, 加 0, sum[1]=1, last[1]=2
- i=3: c=0, b=2≤3, pos=3, last[0]=1, sum[0]=1, 加 1, sum[0]=2, last[0]=3
- i=4: c=1, b=4>3, pos=3, last[1]=2, sum[1]=1, 加 1, sum[1]=2, last[1]=4
- i=5: c=1, b=5>3, pos=3, last[1]=4, sum[1]=2, 加 2, sum[1]=3, last[1]=5
答案累计:0+0+1+1+2=4?不对,应该是 3,说明算法细节需调整。
实际上标准解法:
- 维护 表示当前色调 的客栈总数;
- 维护 表示最近一个可行咖啡店之后色调 的客栈数;
- 当遇到可行咖啡店时,令 (因为之前的客栈都可以和后面的配对);
- 对于当前客栈 ,若 ,则更新 ,然后 (减1是不包括自己和自己配对);
- 若 ,则 。
这样可保证正确。
鉴于细节较复杂,建议直接参考标准代码实现。