SDUSTOJ 1795 哆啦A梦的程序(思路题)
Description
哆啦A梦很喜欢写代码。在缩代码方面,他是一位身经百战的老手。世界各地的OJ上,很多题的最短解答排行榜都有他的身影。这令他感到十分愉悦。
最近,他突然发现,很多时候自己的程序明明看起来比别人的更短,实际代码量却更长。这令他感到很费解。经过一番研究,原来是因为他每一行的缩进都全是由空格组成的,大量的空格让代码量随之增大。
现在设哆啦A梦有一份 n 行的代码,第 i 行有 ai 个空格作为缩进。
为解决这一问题,哆啦A梦要给自己文本编辑器设定一个正整数的默认TAB宽度 x,然后对于每一行,编辑器从头至尾不断把连续 x 个空格替换成一个TAB,直到剩余空格数不足 x 个。
最终缩进所占代码量为空格数与TAB数的和。请你帮哆啦A梦选择一个合适的 x,使得缩进所占代码量最小。
Input
多组数据,对于每一组数据
第一行一个正整数 n,表示代码行数。
接下来 n 行,第 i行一个正整数 ai,为初始时第 i行缩进的空格个数。
n<=10^6,ai<=10^6
Output
一行一个整数,表示缩进所占代码量最小是多少。
Sample Input
3 5 8 8
Sample Output
6
思路:
这道题是山科第三届校赛的题,我们队一路领先,直到最后20分钟被这道题绝杀了。。
真的是一时想不出好的思路,练得太少了,弱就是弱
这道题据出题人说正解是nlogn的复杂度,想好了思路就很简单,但是三分答案也能过
赛后整理了一下,说一下我的做法吧
枚举x(o(n)),每一层以x长度分段
也就是for(int j=1;j*x<=n;j++)这样分
每一个x长度的段里所有数的个数和所有数的和都可以o(n)预处理
然后当前这一个x的ans加上个数*j(除法的值),再加上这一层的和减去着一层的个数*i*j(取模的值)
这样每一个x都可以给出一个确定的答案
时间复杂度就是O(n/1+n/2+n/3+...+n/n)=O(nlogn)的了
可能我写的比较复杂、、比标程长,也慢(实力差距~)
/* *********************************************** Author :devil Created Time :2016/4/26 16:10:39 ************************************************ */ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <cmath> #include <stdlib.h> using namespace std; typedef long long LL; const int N=2e6+7; int a[N],b[N]; long long sum[N]; int main() { //freopen("in.txt","r",stdin); int n,x; while(~scanf("%d",&n)) { int ma=0; memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(sum,0,sizeof(sum)); for(int i=0;i<n;i++) { scanf("%d",&x); ma=max(ma,x); a[x]++; } for(int i=1;i<=ma*2+1;i++) { sum[i]=sum[i-1]+a[i]*i; b[i]=b[i-1]+a[i]; } LL ans=1e12+10; for(int i=1;i<=ma;i++) { LL now=sum[i-1]; for(int j=1;i*j<=ma;j++) now=now+(b[i*(j+1)-1]-b[i*j-1])*j+sum[i*(j+1)-1]-sum[i*j]-(b[i*(j+1)-1]-b[i*j])*j*i; ans=min(ans,now); } printf("%lld\n",ans); } return 0; }