水(NOIP模拟赛Round #10)

题目描述:

小Z有一个长度为的数列。他有次令人窒息的操作,每次操作可以使某个数字。他当然是希望这些数字的乘积尽量小了。为了简化题目,你只需输出操作完成后的数列即可。

————————————————我是分割线————————————————

这道题目,我们可以先自己手动模拟一遍,就能发现,首先我们需要尽量让乘积最小,那么首先我们希望乘积为负数,

所以假设一开始的时候乘积为整数,我们先拿出绝对值最小的那个数,如果是正数就-x,如果是负数就+x直到乘积变为负数。

在乘积变为负数之后,我们来看一个问题:

3 4 6 3个数中,在任意一个数上+1,问加在哪个数的时候,使他们的乘积增加最大?显然是3。所以在乘积为负的时候,我们每次取绝对值最小的数让他的绝对值变大即可

下面贴代码

#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
long long aqs(long long a){return a>=0?a:-a;}
struct number{
    long long num,opt;
    friend bool operator <(number a,number b){
        if(aqs(a.num)==aqs(b.num))return a.num>b.num;
        return aqs(a.num)>aqs(b.num);
    }
}qaq[200005];
int zheng=1,n,k,x;
priority_queue<number>q;
bool cmp(number a,number b){
    return a.opt<b.opt;
}
int main(){
    scanf("%lld%lld%lld",&n,&k,&x);
    for(int i=1;i<=n;i++){
        scanf("%lld",&qaq[i].num);
        qaq[i].opt=i;
        q.push(qaq[i]);
        if(qaq[i].num<0)zheng=(zheng==1)?0:1;
    }
    for(int i=1;i<=k;i++){
        number tmp=q.top();
        q.pop(); 
        if(zheng==1){
            bool now=(tmp.num>=0);
            if(now)tmp.num-=x;else tmp.num+=x;
            q.push(tmp);
            if((tmp.num<0&&now)||(tmp.num>0&&!now))zheng=0;
        }
        else {
            if(tmp.num>=0){
                tmp.num+=x;
                q.push(tmp);
            }
            else tmp.num-=x,q.push(tmp);
        }
    }
    for(int i=1;i<=n;i++){
        qaq[i]=q.top();q.pop();
    }
    sort(qaq+1,qaq+n+1,cmp);
    for(int i=1;i<n;i++)printf("%lld ",qaq[i].num);
    printf("%lld
",qaq[n].num);
    return 0;
}
原文地址:https://www.cnblogs.com/ghostfly233/p/7093868.html