传送门:点击打开链接
每日打卡(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]);
}
很值得思考的一道题。