【UOJ#21】【UR#1】缩进优化

我好弱啊,什么题都做不出来QAQ

原题:

小O是一个热爱短代码的选手。在缩代码方面,他是一位身经百战的老手。世界各地的OJ上,很多题的最短解答排行榜都有他的身影。这令他感到十分愉悦。

最近,他突然发现,很多时候自己的程序明明看起来比别人的更短,实际代码量却更长。这令他感到很费解。经过一番研究,原来是因为他每一行的缩进都全是由空格组成的,大量的空格让代码量随之增大。

现在设小O有一份 n 行的代码,第 i 行有 ai 个空格作为缩进。

为解决这一问题,小O要给自己文本编辑器设定一个正整数的默认TAB宽度 x,然后对于每一行,编辑器从头至尾不断把连续 x 个空格替换成一个TAB,直到剩余空格数不足 x 个。

最终缩进所占代码量为空格数与TAB数的和。请你帮小O选择一个合适的 x,使得缩进所占代码量最小。

n,ai<=10^6

恩一个比较简单的思路是枚举塊的大小,然后暴力计算答案,令M为最大的aiO(nM)可以拿到20分

然后发现暴力计算的时候相同的ai可以合并起来,这样可以搞成O(M^2)的因为有两个点M比较小n比较大所以可以拿到40分

如果tab的长度是x那么没多换一个tab就减少x-1个空格,所以最终答案是n-(x-1)*Σai/x,接下来最大化(x-1)*Σai/x

还是枚举x,每次计算Σai/x,直接计算不太好算,就枚举ai/x的值,在输入ai后用sj记录ai==j的有多少个,枚举ai/x的值后就可以快速通过s计算个数再乘上ai/x这个值得到结果

有一个结论,Σ_{i=1}^{n}1/i=O(logn)

所以这个做法最终是O(MlogM)的,就可以ac辣

我好弱啊,NOI怎么玩嘛QAQ

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 #define ll long long
 8 const ll inf=(ll)2e18;
 9 int rd(){int z=0,mk=1;  char ch=getchar();
10     while(ch<'0'||ch>'9'){if(ch=='-')mk=-1;  ch=getchar();}
11     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
12     return z*mk;
13 }
14 int n,a[1100000];  int mx=0;
15 ll s[1100000];
16 ll ans=0;
17 int main(){freopen("ddd.in","r",stdin);
18     cin>>n;
19     for(int i=1;i<=n;++i)  a[i]=rd(),mx=max(mx,a[i]),++s[a[i]];
20     for(int i=1;i<=mx;++i)  s[i]+=s[i-1];
21     for(int i=1;i<=mx;++i){
22         int jjj=mx/i;  ll bwl=0;
23         for(int j=1;j<=jjj;++j)  bwl+=(s[(j+1)*i-1>mx?mx:(j+1)*i-1]-s[j*i-1])*j;
24         ans=max(ans,(i-1)*bwl);
25     }
26     ll bwl=0;
27     for(int i=1;i<=n;++i)  bwl+=a[i];
28     cout<<bwl-ans<<endl;
29     return 0;
30 }
View Code
原文地址:https://www.cnblogs.com/JSL2018/p/6898027.html