福建工程学院第十四届ACM程序设计大赛 - E - 外传:小晋逃生记

http://www.fjutacm.com/Contest.jsp?cid=705#P4
其实想清楚了就很简单,之前想了很多种方法,以为是二分什么的,看起来就像是一个单峰函数。但是发现直接暴力一波就行了。
不知道有没有人会来搜到我的题解?ID是Yinku2017。

题意:求\(x\)使得\(\sum\limits_{i=1}^{n}[a_i/x]+a_i\%x\)

首先把取余运算换成减法。提公因式。
\(\sum\limits_{i=1}^{n}[a_i/x]+a_i\%x=\sum\limits_{i=1}^{n}{[a_i/x]+a_i-x[a_i/x]}=\sum\limits_{i=1}^{n}a_i+\sum\limits_{i=1}^{n}{(1-x)[a_i/x]}\)
发现什么?枚举x,根据某个n/1+n/2+n/3+...+n/n=nlogn的式子,前缀和计算出后半部分的值。恰好a_i最大就是1e6,可以这么搞,估计这道题已经设计好a_i就是1e6的。

小心溢出就可以了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int n;
int a[1000005]={};
int pa[2000005]={};

int maxa=0;
ll sum=0;
ll minans=0;

int main() {
#ifdef Yinku
    freopen("Yinku.in","r",stdin);
#endif // Yinku
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int t;
        scanf("%d",&t);
        if(t>maxa)
            maxa=t;
        sum+=t;
        a[t]++;
    }

    for(int i=1;i<=maxa*2;i++){
        pa[i]=pa[i-1]+a[i];
    }

    for(int d=2;d<=maxa;d++){
        ll tminans=0;
        int c=(maxa+d-1)/d;
        for(int j=1;j<=c;j++){
            if(j*d>maxa)
                break;
            tminans+=1ll*(pa[(j+1)*d-1]-pa[j*d-1])*j;
        }

        tminans*=(1ll-d);
        if(minans>tminans)
            minans=tminans;
    }

    printf("%lld\n",sum+minans);
}

猜你喜欢

转载自www.cnblogs.com/Yinku/p/10862779.html