【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 }