题目大意:给你n个数,最多有k次操作,每次操作可以将一个任意一个数加上x或者减去x,问你经过k次操作
之后,满足n个数乘积最小的改变后的序列。
思路:我们先考虑原序列由奇数个负数,那么我们只要将n个数的绝对值全部加入优先队列,然后每次操作取出
最小值,如果是负数能减去x,如果是正数加上x,这样进行将会得到最优解。
再考虑没有负数是偶数个的情况,那么我们如果n个数中的绝对值的最小值小于x*k,则我们将这个绝对值
最小的数变成反号,然后就变成了第一种情况。 如果n个数中的绝对值的最小值大于等于x*k,如果这个数是正
数则减去x*k,负数则加上x*k。
有0的情况需要特殊处理一下,细节比较多,不太好写。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #define pii pair<long long,int> 3 #define mk make_pair 4 #define fi first 5 #define se second 6 #define ll long long 7 using namespace std; 8 const int N=2*1e5+5; 9 int n; 10 long long a[N],k,x,cnt1=0,cnt2=0; 11 pii mn,_mn; 12 priority_queue<pii,vector<pii>,greater<pii> > Q; 13 int main() 14 { 15 mn.fi=1e9+10,_mn.fi=1e9+10; 16 mn.se=0,_mn.se=0; 17 scanf("%d%lld%lld",&n,&k,&x); 18 for(int i=1;i<=n;i++) 19 { 20 scanf("%lld",&a[i]); 21 if(a[i]<0) 22 { 23 cnt1++; 24 _mn=min(_mn,mk(-a[i],i)); 25 } 26 else if(a[i]>0) mn=min(mn,mk(a[i],i)); 27 else cnt2++; 28 } 29 if(cnt2>k) 30 { 31 for(int i=1;i<=n;i++) printf("%lld ",a[i]); 32 return 0; 33 } 34 if(cnt2) 35 { 36 bool flag=false; 37 for(int i=1;i<=n;i++) 38 { 39 if(a[i]!=0) continue; 40 if(!(cnt1&1)) 41 { 42 a[i]-=x; 43 cnt1++; 44 } 45 else a[i]+=x; 46 k--; 47 } 48 } 49 if(!(cnt1&1)) 50 { 51 ll w=k*x; 52 if(mn.fi<=_mn.fi) 53 { 54 if(mn.fi<w) 55 { 56 cnt1++; 57 int u=(mn.fi+1)/x; 58 if((mn.fi+1)%x!=0) u++; 59 k-=u; 60 a[mn.se]-=u*x; 61 } 62 else a[mn.se]-=w,k=0; 63 } 64 else 65 { 66 if(_mn.fi<w) 67 { 68 cnt1--; 69 int u=(_mn.fi+1)/x; 70 if((_mn.fi+1)%x!=0) u++; 71 k-=u; 72 a[_mn.se]+=u*x; 73 } 74 else a[_mn.se]+=w,k=0; 75 } 76 } 77 if(cnt1&1) 78 { 79 for(int i=1;i<=n;i++) 80 { 81 if(a[i]==0) 82 { 83 a[i]+=x; 84 k--; 85 } 86 Q.push(mk(abs(a[i]),i)); 87 } 88 while(k--) 89 { 90 pii cur=Q.top(); Q.pop(); 91 if(a[cur.se]<0) a[cur.se]-=x; 92 else a[cur.se]+=x; 93 Q.push(mk(abs(a[cur.se]),cur.se)); 94 } 95 } 96 for(int i=1;i<=n;i++) printf("%lld ",a[i]); 97 puts(""); 98 return 0; 99 }