专栏文章
题解:CF1552H Guess the Perimeter
CF1552H题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mipl42xu
- 此快照首次捕获于
- 2025/12/03 13:46 3 个月前
- 此快照最后确认于
- 2025/12/03 13:46 3 个月前
闲话:写了一个基于一点点数论的做法,交上去过了,然后发现题解区没有,而且貌似做法更简单,遂写题解。
首先注意到,选点集的全集可以求出面积,这样就把问题转化成了 次求矩形一条边的长度。
记矩阵水平于一行方向的边为长,另一边为宽。
不妨考虑一个看起来就很假的方法:选择一部分整行,答案与面积一定都是长的倍数,将得到的答案与面积取 ,得到长的长度。
令选择的与矩阵有交的行数量为 。
显然,这在 与矩阵宽不互质的时候会错。
如何解决这个问题呢?
可以刻画这个方法正确的时候,选择的行可以长什么样。
注意到,当宽为奇数时,只要隔一行选一行就是对的。
证明:设矩形宽为 ,其一定为奇数,则在这种情况下 或 。
利用定理 :
-
若 ,。
-
若 ,。
证毕。
当宽为偶数怎么办呢?
注意到当宽为偶数时,可以把原问题进行放缩,即删掉所有未被选择的行,把这一次的答案当成新矩形的面积,转化成子问题,这样对正确性一定不会有影响。
在我们不知道宽奇偶性的情况下,也就是对于步长为 的所有情况都查一次,找到尽可能大的 满足查出的答案不为 ,然后求 。
因为 的答案为 ,易证放缩到 时宽度为奇数,根据刚才奇数的想法,这样做就是对的。
这样类似于一个倍增,次数是 即 的,可以做到 次。
然而题目要求 次,不难想到做法应该是 级别的。
我们刚才倍增每次查的其实是相互独立的,并且注意到答案具有单调性,即只需要二分出最后一个答案不为 的 即可,可以做到 次。
加上一开始查的面积,一共是 次。
核心代码:
Cnamespace Junounly
{
int ask(int x)
{
cout<<"? "<<' '<<200*(200/x)<<endl;
for(int i=x;i<=200;i+=x)
for(int j=1;j<=200;j++)
cout<<i<<' '<<j<<' ';
cout<<endl;
int res;
cin>>res;
return res;
}
void main()
{
int sum=ask(1),l=0,r=7,res=114514;
for(;l<r;)
{
int mid=(l+r+1)>>1,now=ask(1<<mid);
if(now) l=mid,res=now;
else r=mid-1;
}
int A=114514;
if(res) A=__gcd(res,sum);
else A=1;
cout<<"! "<<(A+sum/A-2)*2<<endl;
}
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...