CF859B Lazy Security Guard题解

也许会更好的阅读体验

一道橙题而已,各种乱搞都能过

玄学做法登场

看到题解区的大佬千篇一律,都简单分析做了一下,核心代码仅三行,蒟蒻打算给题解增加些新鲜的血液(虽说运行效率低点,但足以通过本题)。

首先,要周长最短,肯定不能让三个正方形拼成凹进去的样子,这样会让周长更长,肯定不是最优解。所以,把每条边进行适当平移后,一定能拼成一个矩形的轮廓

接下来,我们为了取到最优值,就要看 \(m\) 个正方形拼成的矩形的周长最小是多少( \(n \le m\)\(m\in Z\),令这个值是 \(a_m\) ),答案就是 \(\forall m,\min \lbrace a_m \rbrace\)

由于 \(m\) 是需要能做到的,即它对应的矩形边缘处都要有正方形,就有 \(m \le \lceil n \div 2 \rceil ^2\)。但是这样还是不行的,\(n \le 10^6\),时间爆掉,需要一些玄学优化。

如果正方形沿着边缘铺开很薄的几圈,和把它们铺成又窄又长的矩形无异,而我们可以很容易证明长宽越接近,周长越小。

于是我们可以推测,\(m\)\(n\) 不会大多少,\(n\) 最大是 \(10^6\),盲猜一下最多大几千这样吧。这个我不会证,但是显然是正确的(至少在这么小范围是正确的,如果有人能证明出来符合条件的 \(m\)\(n\) 大的值在某个多项式结果内,请联系作者,我会尽快补上过程)。

至于实现起来非常简单,即算出上文提到的 \(a_m\) 就没问题了,若暴力判断时限有点紧,所以我就用了类似埃氏筛的东西算,具体见代码。

Code:

#include<bits/stdc++.h>
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define inf 0x7fffffff
#define v e[i].y
using namespace std;
inline ll read(){
    char ch=getchar();ll x=0,w=1;
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();return x*w;
}
inline void write(ll x){
	if(x<0)x=-x,putchar('-');
    if(x<10){putchar(48+x);return;}
    write(x/10),putchar((x+10)%10+48);
}
int n,p[2000005],ans;
int main(){
    ans=inf;
    for(int i=1;i<=1e6+2000;i++){
        for(int j=i;j<=1e6+2000;j+=i)p[j]=max(p[j],min(j/i,i));
    }
    n=read();
    for(int i=n;i<=1e6+2000;i++)ans=min(ans,(i/p[i]+p[i])*2);
    write(ans);
    return 0;
}
posted @ 2022-07-19 17:27  mcDinic  阅读(35)  评论(0编辑  收藏  举报