zoukankan      html  css  js  c++  java
  • ●UOJ 21 缩进优化

    题链:

    http://uoj.ac/problem/21

    题解:

    。。。技巧题吧

    先看看题目让求什么:

    令$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;
    }
    

      

  • 相关阅读:
    PHP __autoload()方法真的影响性能吗?
    MYSQL 逻辑架构
    Ajax.dll的初探
    教育技术反思
    祝天下所有的老师教师节快乐
    Asp.net+Xml+js实现无线级下拉菜单
    有调查就有发言权
    控件事件神奇实效
    Inspiration 7.6使用时出现的问题
    最常用的加密类
  • 原文地址:https://www.cnblogs.com/zj75211/p/8298305.html
Copyright © 2011-2022 走看看