题解 [CF1672E] notepad.exe

传送门

不大会,赛时差点做睡着了

发现 \(\sum len\) 是可以问出来的
考虑令 \(S=(\sum len)+n-1\)
这个东西就是 \(h=1\) 时最小的 \(w\),可以二分出来
那么对于一个 \(h\),有意义的 \(S'\in[S-h+1, S]\)
而且要求 \(h\mid S'\),那么在这个范围内只有一个合法的 \(w\)
则枚举取到最优解的 \(h\),只需要 check \(w=\lfloor\frac{S}{h}\rfloor\) 即可
注意边界问题,二分时左边界为 1 而非 0
复杂度 $O(n+\log2000n)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 100010
#define ll long long
#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}			
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, mlen, ans=INF;

int qans(int x) {cout<<"? "<<x<<endl; fflush(stdout); cin>>x; return x;}

signed main()
{
	cin>>n;
	int l=1, r=5000000, mid;
	int lim=qans(r);
	while (l<=r) {	
		mid=(l+r)>>1;
		if (qans(mid)==lim) r=mid-1;
		else l=mid+1;
	}
	mlen=r+1;
	for (int i=1; i<=n; ++i) {
		if (qans(mlen/i)==i) ans=min(ans, mlen/i*i);
	}
	cout<<"! "<<ans<<endl;
	fflush(stdout);
	
	return 0;
}
posted @ 2022-04-24 09:58  Administrator-09  阅读(2)  评论(0编辑  收藏  举报