L1-7 撒狗粮

网络上称一对情侣秀恩爱为“撒狗粮”,因为单身人士统称为“单身狗”。
在一个大型聚会上,所有宾客被安排坐在一张长条宴会桌边。如果一对情侣坐在一起,那么他们两人身边的单身狗就会被撒一脸狗粮;如果他们没有坐在一起,那么所有被夹在他们两人之间的单身狗都会被撒一脸狗粮。
本题就请你找出被撒狗粮最多(以“脸”为单位)的那位单身人士。

输入格式:

输入第一行给出一个正整数 N(≤ 50 000),是已知情侣的对数;随后 N 行,每行给出一对情侣——为方便起见,每人对应一个 ID 号,为 5 位数字(从 00000 到 99999),ID 间以空格分隔;之后给出一个正整数 M(≤ 80 000),为参加派对的总人数;随后一行按座位从左到右的顺序给出这 M 位客人的 ID,以空格分隔。题目保证无人脚踩两条船。

输出格式:

在一行中输出被撒狗粮最多的单身人士。如果不唯一,按 ID 递增顺序列出。ID 间用 1 个空格分隔,行的首尾不得有多余空格。
题目保证至少有一个输出。

输入样例:

4
11111 22222
33333 44444
55555 66666
77777 88888
10
11111 33333 88888 22222 23333 55555 66666 10000 44444 12345

输出样例:

10000 23333 88888

注意:88888 虽然有伴侣,但在聚会上是单身。

代码长度限制	16 KB
时间限制	400 ms
内存限制	64 MB
栈限制	8192 KB

分析

情侣坐在一起则给两人周围撒狗粮,分开坐则给中间夹着的所有人撒狗粮。于是我们可以先记录下每对情侣的编号,然后将座位上的每对情侣标记下来,然后从左往右遍历,遇到情侣就按照题意所做。

首先,我用unordered_map<string,string>来记录下每对情侣(无序map是线性时间复杂度)

unordered_map<string,string> cpl;
	cin>>n;
	string a,b;
	for(int i=0;i<n;i++){
		cin>>a>>b;
		cpl[a]=b;
	}

然后,我用vector num(N);记录座位上每个人的编号,vector d(N,0),id(N);分别记录座位上每个人的狗粮和对应情侣的下标。这样就可以知道,被标记的两个人是否是同一情侣了。unordered_map<string,int> swt;来快速实现按值查找

vector<int> d(N,0),id(N);
vector<string> num(N);
unordered_map<string,int> swt;//swt:编号to下标
	for(int i=0;i<m;i++){
		cin>>num[i];
		id[i]=i;//初始化
		swt[num[i]]=i;
	}
	for(int i=0;i<m;i++){
		if(cpl.find(num[i])!=cpl.end()&&swt.find(cpl[num[i]])!=swt.end()){//如果此人有情侣并且对象在此次宴席上
			id[i]=swt[cpl[num[i]]];//分别赋值对象的下标
			id[swt[cpl[num[i]]]]=i;
		}
	}

最后,从左到右遍历,按题目要求模拟,最后用结构体存储每个人的信息,排序再输出。

bool ok(const int &i) {//若i不越界且此人为单身
	return i>=0&&i<m&&id[i]==i;
}
struct node{
	int a;//狗粮数 
	string b;//编号
	bool operator<(const node s)const{
		if(a!=s.a)return a>s.a;
		return b<s.b;
	} 
};
	for(int i=0;i<m;i++){
		if(id[i]>i){
			if(id[i]==i+1){
				if(ok(i-1))d[i-1]++;
				if(ok(id[i]+1))d[id[i]+1]++;
			}else{
				for(int j=i+1;id[j]!=i;j++){
					if(ok(j))d[j]++;
				}
			}
		}
	}
	vector<node> vec;
	for(int i=0;i<m;i++){//if(d[i]>0)不可以加此条件,因为有可能一对情侣都没有 
		vec.push_back({d[i],num[i]});
	}
	sort(vec.begin(),vec.end());
	cout<<vec[0].b;
	for(int i=1;i<vec.size()&&vec[i].a==vec[i-1].a;i++){
		cout<<" "<<vec[i].b;
	}
	cout<<endl;

完整代码得出

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N=80008;
unordered_map<string,string> cpl;//cpl:情侣编号,swt:编号to下标
unordered_map<string,int> swt;
int n,m;
vector<int> d(N,0),id(N);
vector<string> num(N);
bool ok(const int &i) {
	return i>=0&&i<m&&id[i]==i;
}
struct node {
	int a;//狗粮数
	string b;//编号
	bool operator<(const node &s)const {
		if(a!=s.a)return a<s.a;
		return b>s.b;
	}
};
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	string a,b;
	for(int i=0; i<n; i++) {
		cin>>a>>b;
		cpl[a]=b;
	}
	cin>>m;
	for(int i=0; i<m; i++) {
		cin>>num[i];
		id[i]=i;
		swt[num[i]]=i;
	}
	for(int i=0; i<m; i++) {
		if(cpl.find(num[i])!=cpl.end()&&swt.find(cpl[num[i]])!=swt.end()) {
			id[i]=swt[cpl[num[i]]];
			id[swt[cpl[num[i]]]]=i;
		}
	}
	int w=0;
	for(int i=0; i<m; i++) {
		if(id[i]>i) {
			if(id[i]==i+1) {
				if(ok(i-1))d[i-1]++;
				if(ok(id[i]+1))d[id[i]+1]++;
			}
			w++;
		} else if(id[i]==i) {
			d[i]+=w;
		} else {
			w--;
		}
	}
	priority_queue<node> que;
	for(int i=0; i<m; i++) {
		//if(d[i]>0)不可以加此条件,因为有可能一对情侣都没有
		que.push({d[i],num[i]});
	}
	node last=que.top();
	que.pop();
	cout<<last.b;
	while(!que.empty()&&que.top().a==last.a) {
		cout<<" "<<que.top().b;
		que.pop();
	}
	cout<<endl;
	return 0;
}

最后提交结果,很好,时间超时!!!!!
在这里插入图片描述
这里我们忽略了一个点,时间限制为400ms,N(≤ 50 000), M(≤ 80 000)用sort排序vector其实没问题,真正的问题出在这里

	for(int i=0;i<m;i++){
		if(id[i]>i){
			if(id[i]==i+1){
				if(ok(i-1))d[i-1]++;
				if(ok(id[i]+1))d[id[i]+1]++;
			}else{
				for(int j=i+1;id[j]!=i;j++){
					if(ok(j))d[j]++;
				}
			}
		}
	}

我们注意到出现了两层循环,如果M和N均取最大,且宴席上N对情侣的话那么我们的时间复杂度可以高达O(M^N)这是非常可怕的时间规模。因此,出题人的意图肯定不想我们就这么简单用两层循环就过了。不用两层循环难道用一层?bingo!!
我们可以用一个w来表示当前元素所处在的w对情侣之间因此,每遇到左人就w++,遇到右人就w–(左人是指一对情侣中宴席上靠左的那一方,右人同理),然后如果遍历到的此人单身则d[i]+=w.详细代码如下

int w=0;
	for(int i=0; i<m; i++) {
		if(id[i]>i) {//遇到左人
			if(id[i]==i+1) {//当两人坐在一起需要特判一下
				if(ok(i-1))d[i-1]++;
				if(ok(id[i]+1))d[id[i]+1]++;
			}
			w++;
		} else if(id[i]==i) {//此人单身
			d[i]+=w;
		} else {//遇到右人
			w--;
		}
	}

修改代码如下,这里我还用了优先队列输出结果,小小地再优化一下

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N=80008;
unordered_map<string,string> cpl;//cpl:情侣编号,swt:编号to下标
unordered_map<string,int> swt;
int n,m;
vector<int> d(N,0),id(N);
vector<string> num(N);
bool ok(const int &i) {
	return i>=0&&i<m&&id[i]==i;
}
struct node {
	int a;//狗粮数
	string b;//编号
	bool operator<(const node &s)const {
		if(a!=s.a)return a<s.a;
		return b>s.b;
	}
};
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	string a,b;
	for(int i=0; i<n; i++) {
		cin>>a>>b;
		cpl[a]=b;
	}
	cin>>m;
	for(int i=0; i<m; i++) {
		cin>>num[i];
		id[i]=i;
		swt[num[i]]=i;
	}
	for(int i=0; i<m; i++) {
		if(cpl.find(num[i])!=cpl.end()&&swt.find(cpl[num[i]])!=swt.end()) {
			id[i]=swt[cpl[num[i]]];
			id[swt[cpl[num[i]]]]=i;
		}
	}
	int w=0;
	for(int i=0; i<m; i++) {
		if(id[i]>i) {
			if(id[i]==i+1) {
				if(ok(i-1))d[i-1]++;
				if(ok(id[i]+1))d[id[i]+1]++;
			}
			w++;
		} else if(id[i]==i) {
			d[i]+=w;
		} else {
			w--;
		}
	}
	priority_queue<node> que;
	for(int i=0; i<m; i++) {
		//if(d[i]>0)不可以加此条件,因为有可能一对情侣都没有
		que.push({d[i],num[i]});
	}
	node last=que.top();
	que.pop();
	cout<<last.b;
	while(!que.empty()&&que.top().a==last.a) {
		cout<<" "<<que.top().b;
		que.pop();
	}
	cout<<endl;
	return 0;
}

代码运行过程展示
在这里插入图片描述

提交结果
在这里插入图片描述

  • 12
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值