题链:
题解:
。。。技巧题吧
先看看题目让求什么:
令$F(x)=sum_{i=1}^{n}(lfloor a[i]/x floor +a[i]$%$x)$
要求输出最小的F(x)。
首先不难看出,x的取值不会超过最大的a[i]+1,(因为之后的答案都和x==a[i]+1时的答案相同)
把式子化为如下形式:
$F(x)=sum_{i=1}^{n}(lfloor a[i]/x floor +(a[i]-lfloor a[i]/x floor x))$
$quadquad=sum_{i=1}^{n}(a[i]-lfloor a[i]/x floor (1-x))$
$quadquad=sum-sum_{i=1}^{n}(lfloor a[i]/x floor (1-x))$
$quadquad=sum+sum_{i=1}^{n}(lfloor a[i]/x floor (x-1))$
现在即是要找出最大的$sum_{i=1}^{n}(lfloor a[i]/x floor (x-1))$
然后我们令$t=lfloor a[i]/x floor$
(把a从小到大排序后)对于每一个枚举的x,
不难发现,随着a[i]的增大,t也是在单增,而且t的取值还是一段一段的。
即对于$a[i]∈ [lambda x,(lambda+1)x-1] $,t的取值都是$lambda$
所以我们可以用后缀和或者前缀和的方法对于每一个枚举的x,快速求出$sum_{i=1}^{n}(lfloor a[i]/x floor (x-1))=sum_{i=1}^{n}t (x-1)$
使得总复杂度为 O(NlogN)
代码:
#include<cstdio> #include<cstring> #include<iostream> #define MAXN 1000050 #define INF 0x3f3f3f3f3f3f3f3f using namespace std; int cnt[MAXN]; int main(){ int n,maxa=0; long long ans=0,tmp,sum=0; scanf("%d",&n); for(int i=1,x;i<=n;i++) scanf("%d",&x),cnt[x]++,maxa=max(maxa,x),sum+=x; for(int i=maxa-1;i;i--) cnt[i]+=cnt[i+1]; for(int x=1;tmp=0,x<=maxa;x++){ for(int r=1;r*x<=maxa;r++) tmp+=cnt[r*x]; tmp*=(x-1); if(tmp>ans) ans=tmp; } printf("%lld",sum-ans); return 0; }