TJU-4113- Determine X(数学题)

给出数列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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值