题目来源:http://www.tsinsen.com/A1191
A1191. 选择客栈
时间限制:1.0s 内存限制:128.0MB
试题来源
NOIP2011 提高组
问题描述
丽江河边有 n 家很有特色的客栈,客栈按照其位置顺序从1 到n 编号。每家客栈都按照某一种色调进行装饰(总共k 种,用整数0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖啡店均有各自的最低消费。
两位游客一起去丽江旅游,他们喜欢相同的色调,又想尝试两个不同的客栈,因此决定分别住在色调相同的两家客栈中。晚上,他们打算选择一家咖啡店喝咖啡,要求咖啡店位于两人住的两家客栈之间(包括他们住的客栈),且咖啡店的最低消费不超过p。
他们想知道总共有多少种选择住宿的方案,保证晚上可以找到一家最低消费不超过p元的咖啡店小聚。
输入格式
输入共n+1 行。
第一行三个整数 n,k,p,每两个整数之间用一个空格隔开,分别表示客栈的个数,色调的数目和能接受的最低消费的最高值;
接下来的 n 行,第i+1 行两个整数,之间用一个空格隔开,分别表示i 号客栈的装饰色调和i 号客栈的咖啡店的最低消费。
输出格式
输出只有一行,一个整数,表示可选的住宿方案的总数。
样例输入
5 2 3
0 5
1 3
0 2
1 4
1 5
样例输出
3
数据规模和约定
对于 30%的数据,有n≤100;
对于 50%的数据,有n≤1,000;
对于 100%的数据,有2≤n≤200,000,0<k≤50,0≤p≤100, 0≤最低消费≤100。
-----------------------------------------------------
解题思路
数学题
由于题目只要求解住宿方案个数,不用求住宿方案+咖啡厅碰面方案个数,所以枚举客栈个数。两个客栈一左一右,考虑边读取输入边计算,枚举右边的客栈。
记最低消费不超过p的咖啡厅为“便宜咖啡厅”,记总的住宿方案个数为ans。算法如下:
1. 对于每一个读入的客栈,如果有便宜的咖啡厅,则该客栈左边所有客栈都能住,即ans+=c1[c]
2. 若没有便宜的咖啡厅,则只有该客栈左侧最靠右的有便宜咖啡厅的客栈左侧(包括其自身)的客栈可选,即ans+=c2[c]
3. 维护两个长度为k的数组c1[k]和c2[k]. 每次读入一个颜色为c的客栈,c1[c]++,4. 若该读入的客栈有便宜咖啡厅,则将c1的k个值复制给c2
-----------------------------------------------------
代码
//A1191. 选择客栈 #include<iostream> #include<fstream> using namespace std; const int N_MAX = 200005; const int K_MAX = 55; int c1[K_MAX] = {}; // 0~(i-1)中色调=k的客栈数 int c2[K_MAX] = {}; // 0~last中色调=k的客栈数 int main() { #ifndef ONLINE_JUDGE ifstream fin("A1191.txt"); int n,k,p,i,j,price,c; fin >> n >> k >> p; int last = -1; // 当前最后一个消费小于等于p的咖啡店 long long ans = 0; for (i=0; i<n; i++) { fin >> c >> price; if (price<=p) { last = i; // 最后一个消费小于等于p的咖啡店 } if (i==last) // 如果右侧客栈自带便宜的咖啡馆 { ans += c1[c]; // 则所有左侧的客栈都可以选择 } else // 若右侧客栈没有便宜的咖啡馆 { ans += c2[c]; // 则只有右侧客栈左侧最靠右的便宜咖啡馆左侧(包括其自身)的客栈可选 } c1[c]++; if (i==last) { for (j=0; j<k; j++) { c2[j] = c1[j]; } } } fin.close(); cout << ans; return 0; #endif #ifdef ONLINE_JUDGE int n,k,p,i,j,price,c; cin >> n >> k >> p; int last = -1; // 当前最后一个消费小于等于p的咖啡店 long long ans = 0; for (i=0; i<n; i++) { cin >> c >> price; if (price<=p) { last = i; // 最后一个消费小于等于p的咖啡店 } if (i==last) // 如果右侧客栈自带便宜的咖啡馆 { ans += c1[c]; // 则所有左侧的客栈都可以选择 } else // 若右侧客栈没有便宜的咖啡馆 { ans += c2[c]; // 则只有右侧客栈左侧最靠右的便宜咖啡馆左侧(包括其自身)的客栈可选 } c1[c]++; if (i==last) { for (j=0; j<k; j++) { c2[j] = c1[j]; } } } cout << ans; return 0; #endif }