>Description
>Input
>Output
>解题思路
题意: a n s = Σ ( a i / T A B + a i m o d T A B ) ans=Σ(a_i/TAB+a_i mod TAB) ans=Σ(ai/TAB+aimodTAB),找出TAB和最小的ans,输出最小的ans
通过推算可以得出,ans关于TAB的函数图像大致如下图(左边商大,右边余数大),ans随着TAB的增大不断缩小,到达一个极点后又回升,箭头指向的极点就是我们要求的answer:
所以我们就可以用三分进行查找TAB,使l和r不断靠近极点,最后l和r在一个小距离内就直接暴力求answer
时间复杂度大致为O(nlogn)
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1000005
#define int long long
using namespace std;
int n, m, aa, a[N], ans, l, r, mid1, mid2, cnt[N];
int f (int x)
{
int ret = 0;
for (int i = 1; i <= m; i++)
ret += (a[i] / x + a[i] % x) * cnt[a[i]];
return ret;
}
signed main()
{
scanf ("%lld", &n);
l = 1;
for (int i = 1; i <= n; i++)
{
scanf ("%lld", &aa);
r = max (r, aa);
if (!cnt[aa]) a[++m] = aa;
cnt[aa]++;
} //去重
while (r - l >= 50) //l和r不断靠近,最后暴力求最小值
{
int k = (r - l + 1) / 3;
mid1 = l + k - 1, mid2 = r - k + 1; //加大范围防止重合
if (f (mid1) < f (mid2)) r = mid2;
else l = mid1;
}
ans = 1000000000000ll;
for (int i = l; i <= r; i++)
ans = min (ans, f (i));
printf ("%lld", ans);
return 0;
}