TJU-4113- Determine X(数学题)

来源:互联网 发布:centos 6.8 内核版本 编辑:程序博客网 时间:2024/06/06 07:37

给出数列Ai~An,求

F(x)=i=1N(Aix+Aimodx)

的最小值。


教训:因为不需要使用long long的数组开成了long long,TLE了好多次。

做法:

预处理出f[n](小于等于n有多少个数)和s[n](小于等于n的数之和)。

暴力枚举x(从2到最大的一项),对于每个x,可以把这些数分成若干段,每段具有类似的性质。即Ai / x的值相同。

例如,数列为 2,4,5,6,8,9,13,14.........,当x=5,2,4可以分为1组,5,6可以分为一组,8,9为一组,13,14为一组

枚举Ai/x的值,就可以O(1)计算出这段中Ai/x+Ai%x的值。(tips:A%X=A-(A/X)×X)。设N=max(Ai),均摊的复杂度为O(NlogN)。

#include<cstdio>#include<cstring>#include<algorithm>typedef long long LL;using namespace std;const int MAXM=1E6;int a[MAXM+5],f[MAXM+5];LL  s[MAXM+5];void work(){    int i,j,k,t,m,n,maxa;    LL ans,sum,x,temp,lim;    maxa=0;    scanf("%d",&n);    for(i=0;i<n;i++) scanf("%d",&a[i]),maxa=max(maxa,a[i]);    for(i=0;i<=maxa;i++) s[i]=f[i]=0;    for(i=0;i<n;i++)    {        f[a[i]]++;        s[a[i]]+=(LL)a[i];    }    for(i=1;i<=maxa;i++)    {        f[i]+=f[i-1];        s[i]+=s[i-1];    }    ans=s[maxa];    for(k=2;k<=maxa;k++)    {        sum=0;        for(i=0;i*k<=maxa;i++)        {            int x=max(0,i*k-1);            int y=min(maxa,(i+1)*k-1);            sum+=(LL)i*(LL)(f[y]-f[x]);            sum+=s[y]-s[x]-(LL)(f[y]-f[x])*(LL)i*(LL)k;            if(sum>=ans) break;        }        ans=min(ans,sum);    }    printf("%lld\n",ans);}int main(){    int T;    scanf("%d",&T);    while(T--) work();    return 0;}


0 0
原创粉丝点击