Codeforces eduR42 D(map,set与vector混合运用)

传送门:点击打开链接

每日打卡(1/1)

题目大意:

    给你n个数,要求找出出现超过两次以上的最小的数,并把这两个数删除,加起来后放到这两个数中位置靠后的 位置上。

For example, consider the given array looks like [3,4,1,2,2,1,1][3,4,1,2,2,1,1]. It will be changed in the following way: [3,4,1,2,2,1,1]  [3,4,2,2,2,1]  [3,4,4,2,1]  [3,8,2,1][3,4,1,2,2,1,1] → [3,4,2,2,2,1] → [3,4,4,2,1] → [3,8,2,1]

题目思路:

    进行无限次循环,每次利用map记录下每个数出现的次数,如果>=2,扔到就进行删除添加操作,直到不能继续。

记录一:WA在第五个点

#include<bits/stdc++.h>
using namespace std;
const int maxn = 150005;

int n,temp,sum,mini = maxn,k=0;
map<int,int> mp;
vector<int> a;

int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		int x;
		scanf("%d",&x);
		a.push_back(x);
		mp[x]++;
	}
	map<int,int>::iterator it;
	while(1)
	{
		mp.clear();
		for(int i=0;i<a.size();i++)
		 mp[a[i]]++;
//		for(int i=0;i<n;i++)
//		 cout<<a[i];
//		cout<<endl;
		for(it = mp.begin();;it++)
		{
			if((it->second)>=2) {
				temp = it->first;
				break;
			}
			if(it==mp.end()) {
				temp = -1;
				break;
			}
		}
		if(temp==-1) break;
		int flag = 0,pos;
		for(int i=0;i<a.size();i++)
		{
			if(a[i]==temp&&flag<=1) 
			{
				flag++;
				pos = i;
				a[i] = -1;
			}
			if(flag==2) {
				flag++;
				a.insert(a.begin()+pos,temp*2);
				break;
			}
		}
		for(int i=0;i<a.size();i++)
		{
			if(a[i]==-1)
			 a.erase(a.begin()+i);
		}
	}
	cout<<a.size()<<endl;
	for(int i=0;i<a.size();i++)
	 printf("%d%s",a[i],i==a.size()-1?"\n":" ");
	return 0;
} 

然后等了半小时,发现错误了。。。

爆int了,,,,真是。。。

改成long long后,发现新问题:死循环

事实证明,

for(it = mp.begin();;it++)
{
	if((it->second)>=2) {
		temp = it->first;
		break;
	}
	if(it==mp.end()) {
		temp = -1;
		break;
	}
}

这两个if循环是不能反过来的,因为当迭代器正好指向最后一个时,会先进行第一个判断,改成long long后, map超了范围,但是这个值是大于2的。因此,需要将两个if倒过来判断。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 150005;

int n,sum,mini = maxn,k=0;
long long temp;
map<long long,int> mp;
vector<long long> a;

int main()
{
	a.clear();
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		long long x;
		scanf("%lld",&x);
		a.push_back(x);
	}
	map<long long,int>::iterator it;
	while(1)
	{
		mp.clear();
		for(int i=0;i<a.size();i++)
		 mp[a[i]]++;
//		for(int i=0;i<a.size();i++)
//		 cout<<a[i];
//		cout<<endl;
		for(it = mp.begin();;it++)
		{
			if(it==mp.end()) {
				temp = -1;
				break;
			}
			if((it->second)>=2) {
				temp = it->first;
				break;
			}
			
		}
		if(temp==-1) break;
		int flag = 0,pos;
		for(int i=0;i<a.size();i++)
		{
			if(a[i]==temp&&flag<=1) 
			{
				flag++;
				pos = i;
				a[i] = -1;
			}
			if(flag==2) {
				flag++;
				a.insert(a.begin()+pos,temp*2);
				break;
			}
		}
		for(int i=0;i<a.size();i++)
		{
			if(a[i]==-1)
			 a.erase(a.begin()+i);
		}
	}
	cout<<a.size()<<endl;
	for(int i=0;i<a.size();i++)
	 printf("%lld%s",a[i],i==a.size()-1?"\n":" ");
	return 0;
} 

到此,我们就愉快的TLE了。。

然后,阅读一下他人的做法。

用set来维护,不得不说,,的确很巧妙。。

 .

#include<cstdio>
#include<set>
#define ll long long 
using namespace std;
set<ll> s;
typedef set<ll>::iterator IT;
IT it;
ll x,f[150050],ans[150050],num,tot;
int n;
int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++){
		scanf("%lld",&x);
		it=s.find(x);
		while (it!=s.end()){
			s.erase(it);
			x=x*2;
			it=s.find(x);
		}
		f[i]=x;
		s.insert(x);
	}
	num=tot=s.size();
	for (int i=n;i>=1&#i--)if(s.find(f[i])!=s.end())ans[num--]=f[i],s.erase(f[i]);//从后向前是因为如果出现3个相同的话,是改变前2个,因此将set中的值赋给最后一个
	printf("%d\n",tot);
	for (int i=1;i<=tot;i++)printf("%lld ",ans[i]);
}
很值得思考的一道题。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

总想玩世不恭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值