962D

You are given an array of positive integers. While there are at least two equal elements, we will perform the following operation. We choose the smallest value xx that occurs in the array 22 or more times. Take the first two occurrences of xx in this array (the two leftmost occurrences). Remove the left of these two occurrences, and the right one is replaced by the sum of this two values (that is, 2x2⋅x).

Determine how the array will look after described operations are performed.

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].

If the given array is look like [1,1,3,1,1][1,1,3,1,1] it will be changed in the following way: [1,1,3,1,1]  [2,3,1,1]  [2,3,2]  [3,4].

大致意思就是所有出现次数超过1的元素都只保留第二次出现的,并进行累加,持续进行这个操作,直到所有元素都只出现一次。

开始的时候想用数组的,遍历其中,如果没有重复的就考虑下一个,这样对于某一个i要操作n次,对于所有元素要操作O(n^2),

后来发现,每次要求和,结果可能会变大,所以之前不考虑到元素又要重新去检查,这样复杂度会再次上升,不好。

最后AC方法是用优先队列,队列中存放的是有序二元对(value,index),然后队列的排序方式是value升序,value相同时index

升序,算法操作是,取队首元素,如果和下一个队中元素value相等,意味着在第二个索引处出现了同样的值,我们就要去重了。

#include<iostream>  
#include<stdio.h>  
#include<queue>  
using namespace std;  
//使用优先队列,其中元素类型为pa  
//优先队列的排序根据是value  
//这样的话value小的一定会排在前面  
//每次比较第一个和第二个是否相等  
//如果不相等直接出队  
//如果相等在数组中标记已被删除,然后队列中下一个元素value翻倍  
//只要队列不空,循环此操作  
struct pa  
{  
    long long value;  
    int index;  
  
    bool operator <(const pa& u) const  
    {  
        if(value==u.value)  
            return index > u.index;             //万一两者value相等,要让索引小的删除  
        return value > u.value;  
    }  
};  
//初始化工作  
const int maxn=150000+5;  
//如果元素被删除就改成-1  
long long array[maxn]={0};  
int ans=0;  
  
priority_queue<struct pa> b;  
void delete_same()        
{  
    struct pa u=b.top();         
    b.pop();  
    if(b.empty())  
        return;           
    if(b.top().value==u.value)  
    {  
        //下一个值和他一样,说明有重复  
        struct pa v;  
        v.value=u.value*2;  
        v.index=b.top().index;  
        b.pop();  
        b.push(v);  
        //还得把这个index的值改成-1  
        array[u.index]=-1;  
        array[v.index]*=2;  
        //cout<<u.value<<" has been emerged with "<<u.index<<"and "<<v.index<<endl;  
        ans++;  
    }  
    //如果不相等那就直接出队  
}  
int main()  
{  
    int n;             
    while(scanf("%d",&n)!=EOF){  
    ans=0;  
    for(int i=0;i<n;i++)  
    {  
        scanf("%d",&array[i]);  
        pa newm;  
        newm.value=(long long)array[i];  
        newm.index=i;  
        //cout<<array[i]<<" "<<i<<" is being pushed in"<<endl;  
        b.push(newm);  
    }  
    while(!b.empty())  
    {  
        delete_same();  
    }  
    cout<<n-ans<<endl;  
    for(int i=0;i<n;i++)  
    {  
        if(array[i]>0)  
            cout<<array[i]<<" ";  
    }  
    printf("\n");  
    }  
    return 0;     
}  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值