在openjudge上做的题目,原来是2011年的=====。
题目:
丽江河边有 n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号。每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖啡店均有各自的最低消费。
两位游客一起去丽江旅游,他们喜欢相同的色调,又想尝试两个不同的客栈,因此决定分别住在色调相同的两家客栈中。晚上,他们打算选择一家咖啡店喝咖啡,要求咖啡店位于两人住的两家客栈之间(包括他们住的客栈),且咖啡店的最低消费不超过 p。
他们想知道总共有多少种选择住宿的方案,保证晚上可以找到一家最低消费不超过 p元的咖啡店小聚。
2<=n<=200000, 0<k<=50, 0<=p<=100, 0<=最低消费<=100
也就是找出所有对色调相同的旅馆并且中间的最小费用小于p
首先想到的是 O(n^2)的,想到很容易,但20,000肯定爆炸。
然后想到的是拿一个数组保存相同色调的,可能好一点,万一,万一,万一最坏颜色全部一样(N^2)那就爆炸了。
其实这道题能用滚动数组优化,注意下面这点:
如果 第i+1个色调为k 的客栈 能访问第i个色调为k的客栈,那么对于以后的所有色调为k的客栈都可以访问第i个色调为k的客栈。
简单的说,如果这个客栈能被访问,那么后面所有的同类客栈都可以访问他,毕竟后面到该客栈的费用必定 <=price[i] <= p。
我们只要2个数组
一个用来保存可以直接访问的。
一个用来保存无法访问的;
如果发现连通,那么 可以直接访问的个数 += 无法访问的个数(根据上面的推理,这些客栈都全部通了)
//其实一个也可以,只需要记录色调k客栈出现的次数,然后每次 访问个数 = 出现个数。
另外每个点每个颜色更新一下最短值。
这样在O(nk)就解决了。
#include <iostream>
#include <cstring>
#define inf 0x3f3f3f3f
using namespace std;
int n,k,p;
int direct[51];
int block[51];
int pre[51];
int main()
{
memset(pre,0x3f,sizeof(pre));
int ans = 0;
cin >> n >> k >> p;
int x = 0 , y;
for (int i = 1 ; i <= n ; ++i)
{
cin >> x >> y;
if(pre[x] == inf) //如果路径无穷大 保存
{ //加上必通的
block[x] = 1; //累计数量=1
pre[x] = y; //最低费用为y
for (int j = 0;j < k ;++j)
if (pre[j] != inf)
pre[j] = min (pre[j],y); //如果费用存在,则更新最小费用
continue; //继续循环
}
for (int j = 0;j < k ;++j)
if (pre[j] != inf)
pre[j] = min (pre[j],y); //如果费用存在,则更新最小费用
if(pre[x] <= p) //如果费用满足要求,那么对于后面的客栈,前面的路全通
{
direct[x] += block[x];
block[x] = 1; //不满足数量为 0
pre[x] = y; //最小费用为当前客栈
}
else //如果大于,则卡住 +1
block[x]++;
ans += direct[x]; //加上直接可以取的
}
cout << ans << endl;
}
补:后来改了一下,改成一个数组,两个数组真的啰嗦,直接设个计数器就简单多了,还调整了下代码,主代码大概就20行左右!
#include <iostream>
#include <cstring>
#define inf 0x3f3f3f3f
using namespace std;
int n,k,p;
int direct[51];
int cnt[51];
int pre[51];
int main()
{
memset(pre,0x3f,sizeof(pre));
int ans = 0;
cin >> n >> k >> p;
int x = 0 , y;
for (int i = 1 ; i <= n ; ++i)
{
cin >> x >> y;
cnt[x]++;
if(pre[x] == inf) pre[x] = y;
for (int j = 0;j < k ;++j)
if (pre[j] != inf)
pre[j] = min (pre[j],y); //如果费用存在,则更新最小费用
if(pre[x] <= p) //如果费用满足要求,那么对于后面的客栈,前面的路全通
{
direct[x] = cnt[x] - 1;
pre[x] = y; //最小费用为当前客栈
}
ans += direct[x]; //加上直接可以取的
}
cout << ans << endl;
}