周报素材

发布时间 2023-09-05 19:46:09作者: WW爆米花

A. Set or Decrease

题意:

给定一个长度为n的数组给一个数k,你可以进行一下两种操作

1.数组中的一个数减1

2.用数组中的一个数赋值给数组中的另一个数

(操作1 2 等价)

要求操作次数最小,使数组的和小于等于k

思路:

有两个变量

易得,操作一多,则操作二少
操作一少,则操作二多

枚举操作二的数量,O(n)

当操作二的数量确定,O(1)算出所需的操作一数:ceil((now-k)*1.0/(n-i+1))

即得到最小答案

`

ll ans = 2e18;
cin >> n >> k;
for (int i = 1; i <= n; i++) cin >> s[i];
sort(s + 1, s + 1 + n);
for (int i = 1; i <= n; i++) pre[i] = pre[i - 1] + s[i];
for (int i = 1; i <= n; i++)
{
    ll now = pre[i] + (n - i) * s[1];//先假设拿a[1]换掉最后n-i个数可行
    if (now <= k) ans = min(ans, ll(n - i));//如果可行,直接比较答案
    else//换掉最后n-i数不可行,那么补救的方案就是使a[1]减1
    { //te表示应当再使a[1]减几次1才可行。now-k表示多余的要减掉的
        ll te = ceil((now - k) * 1.0 / (n - i + 1));//分给a[1]和后n-i个数,就等于每1个要减的数,
                                                             //即a[1]要减的数。ceil向上取整                   
        ans = min(ans, ll(n - i + te));
    }
}
cout << ans << endl;

`