每日算法题-正整数数组相等的最小成本问题

问题:

已知A=[a_{0},a_{1},a_{2},....,a_{n-1}], a_{i}都是不超过int的正整数,给两个操作:操作1: 可以将任意一个数a_{i}加1并消耗C1金币操作2:可以将任意两个数a_{i},a_{j} (i!=j)分别加1,并消耗C2金币。现在问最少消耗多少金币能够让A中所有数相等。(n <= 10^6),结果对1000000007取模。

思路:

我们记A中最小元素为a_{min},最大元素为a_{max}

1.如果c2 >= 2*c1 那说明无论如何用操作1都比较划算。

用操作1将A中元素全部加到a_{max},就是答案。

记要加的数和为S_{r}=\sum_{0}^{n-1}(a_{max}-a_{i}),答案是S_{r}*c1

2.如果c2 < 2*c1,

我们第一步要尽可能用操作2将A中元素全部加到a_{max},这样比较划算

如果 a_{max}-a_{min} > S_{r}/2 ,那么用操作2一直操作最小的那个数和其他小于a_{max}的数,最后A会变成n-1个a_{max}, 和1个a_{min}+S_{r}/2

如果a_{max}-a_{min} <= S_{r}/2, 那么如果S_{r}是偶数,一定可以用操作2将A中所有数加到a_{max};那么如果S_{r}是奇数,可以用操作2将A中n-1个数加到a_{max},1个数加到a_{max}-1

下面讨论对最后1个数(即第一种情况的a_{min}+S_{r}/2和第二种情况的a_{max}-1)怎么办。假设最后一个数还剩r就到a_{max}(即最后一个数等于a_{max}-r)。

那么假设最后加到所有数为k+a_{max}, 需要x次操作1和y次操作2,可以得到以下约束条件;

最小化代价:min(x*c1+y*c2),  y = k*(n-1),  k*(n-1)+x = r+k

整理得:需要最小化 min(-k*(n-2)*c1+k(n-1)*c2) = min(r*c1+((n-1)c2-(n-2)c1)k)

如果(n-1)c2>(n-2)c1 k取0最小

如果(n-1)c2<=(n-2)c1 根据这个式子r=k(n-2)+x,k最大取r/(n-2)

代码:
int solution(vector<int>& A, int c1, int c2) {
	if (A.size() == 0) {
		return 0;
	}
	LL res = 0;
	int maxval = 0;
	for (int it: A) {
        maxval = max(it,maxval);
	}
	if (c2 >= 2*c1) {
       for (auto& it: A) {
			res = (res + (maxval - it)*(LL)c1 % mod) %mod;
	    }
	   return res;
	} else {
		int maxr = 0;
	    LL totr = 0;
	    for (auto it:A) {
            maxr = max(maxval-it,maxr);
		    totr += maxval-it;
	    }
	    int r;
	    if (maxr > totr-maxr) {
		    r = maxr-totr+maxr;
			res = (res + (LL)c2*(totr-maxr))%mod;
	    } else {
		    r = totr%2;
            res = (res + (LL)c2*((totr/2)%mod))%mod;
	    }
	   int n = A.size();
	   if (n<=2) {
          return (res + r*(LL)c1%mod)%mod;
	   } else {
		  if ((n-1)*(LL)c2 > (n-2)*(LL)c1) {
			 return (res+r*(LL)c1%mod)%mod;
		  } else {
			int k=r/(n-2);
			int x=r%(n-2);
			return (res+(n-1)*(LL)k*c2%mod + x*(LL)c1%mod)%mod;
		  }
	   }
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值