选择客栈

Description

丽江河边有 n 家很有特色的客栈,客栈按照其位置顺序从1到n编号。每家客栈都按照某一种色调进行装饰(总共k 种,用整数0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖啡店均有各自的最低消费。

两位游客一起去丽江旅游,他们喜欢相同的色调,又想尝试两个不同的客栈,因此决定分别住在色调相同的两家客栈中。晚上,他们打算选择一家咖啡店喝咖啡,要求咖啡店位于两人住的两家客栈之间(包括他们住的客栈),且咖啡店的最低消费不超过p。

他们想知道总共有多少种选择住宿的方案,保证晚上可以找到一家最低消费不超过p元的咖啡店小聚。

Analysis

显而易见的,咖啡店是问题的主体,只要找到满足条件的咖啡店,将其左右各自所有的颜色相同的客栈数相乘的和就是对于此咖啡店的组合数。区间内颜色相同的客栈数怎么算呢,自然是前缀和。到这里还不算结束,因为不同咖啡店的客栈组合有重复的,对于靠后的低价咖啡店,可能包括了前面咖啡店的客栈组合。为了防止重复,只要计算左区间客栈的时候不计已算过的。记录一下每个低价咖啡馆前最近的低价咖啡馆,左区间客栈只需考虑此段区间即可。

真没看出来动规解法。

Code

#include <bits/stdc++.h>

int n,m,p,cl[200010],cost[200010],prev[200010],sum[51][200010];
long long ans;

int read(){
	int f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	int get=0;
	while(ch>='0'&&ch<='9'){
		get=(get<<1)+(get<<3)+ch-'0';
		ch=getchar();
	}
	return get;
}

int main(){
	freopen("hotel.in","r",stdin);
	freopen("hotel.ans","w",stdout);
	std::cin>>n>>m>>p;
	for(int i=1;i<=n;i++)
		cl[i]=read(),cost[i]=read();
	int sub=0;
	for(int i=1;i<=n;i++)
		if(cost[i]<=p){
			prev[i]=sub;
			sub=i;
		}
	for(int i=1;i<=n;i++){
		for(int j=0;j<m;j++)
			sum[j][i]=sum[j][i-1];
		sum[cl[i]][i]++;
	}
	for(int i=1;i<=n;i++)
		if(cost[i]<=p){
			for(int j=0;j<m;j++)
				ans+=(sum[j][i]-sum[j][prev[i]])*(sum[j][n]-sum[j][i-1]);
			ans--;
		}
	std::cout<<ans<<std::endl;
	return 0;
}
posted @ 2018-08-17 11:38  Srzer  阅读(147)  评论(0编辑  收藏  举报