Codeforces 721D [贪心]

/*
不要低头,不要放弃,不要气馁,不要慌张。
题意:
给一列数a,可以进行k次操作,每次操作可以选取任意一个数加x或者减x,x是固定的数。求如何才能使得这个数列所有数乘积最小。
思路:
贪心...讨论这列数中负数的个数,如果为偶数,那么把数列中绝对值最小的数使其往0的方向前进。
如果为奇数,同样选择绝对值最小的数,使其往背离0的方向前进。
道理很简单...自己写写就看出来了...
wa点:
有一个细节没处理好,如果经过某次操作某个数变成0了...那么我们的负数记录并没有更新...
默认下一次会减...因为我们需要构造一个新的负数...所以这里gg了...
*/








#include<bits/stdc++.h>
#define N 200050
using namespace std;
long long jilu[N];
long long ans[N];
struct st{
    st(){}
    st(long long a,int aa){
        bb=a;
        jue=max(a,-a);
        id=aa;
    }
    int id;
    long long bb,jue;
};
bool operator < (const st &a,const st &b){
    return a.jue<b.jue;
}
multiset<st> ms;
int main()
{
    int n,k;
    long long x;
    int zero=0,zheng=0,fu=0;
    scanf("%d%d%lld",&n,&k,&x);
    int ddd=0;
    for(int i=1;i<=n;i++){
        scanf("%lld",jilu+i);
        if(jilu[i]!=-1000000000)ddd++;
        if(jilu[i]==0)zero++;
        else if(jilu[i]>0)zheng++;
        else fu++;
    }
    for(int i=1;i<=n;i++)ms.insert(st(jilu[i],i));
    st tmp;
    for(int i=1;i<=k;i++){
        tmp=*ms.begin();
        ms.erase(ms.begin());
        if(fu%2==0){
            if(tmp.jue<=x)fu++;
            if(tmp.bb>=0){
                tmp.bb-=x;
                if(tmp.bb==0&&i!=k){
                    i++;
                    tmp.bb-=x;
                }
            }
            else{
                tmp.bb+=x;
                if(tmp.bb==0&&i!=k){
                    tmp.bb+=x;
                    i++;
                }
            }
            ms.insert(st(tmp.bb,tmp.id));
        }
        else{
            if(tmp.bb>=0)tmp.bb+=x;
            else tmp.bb-=x;
            ms.insert(st(tmp.bb,tmp.id));
        }
    }
    multiset<st>::iterator it;
    for(it=ms.begin();it!=ms.end();it++){
        ans[it->id]=it->bb;
    }
    for(int i=1;i<=n;i++){
        printf("%lld ",ans[i]);
    }
}
原文地址:https://www.cnblogs.com/tun117/p/5925456.html