题意
This is an interactive problem.
Vasya and Petya are going to play the following game: Petya has some positive integer number (a). After that Vasya should guess this number using the following questions. He can say a pair of non-negative integer numbers ((x,y)). Petya will answer him:
- "
x
", if ((x mod a)≥(y mod a)). - "
y
", if ((x mod a)<(y mod a)).
We define ((x mod a)) as a remainder of division (x) by (a).
Vasya should guess the number (a) using no more, than 60 questions.
It's guaranteed that Petya has a number, that satisfies the inequality (1≤a≤10^9).
Help Vasya playing this game and write a program, that will guess the number (a).
分析
猜数题,想到倍增定范围然后二分答案,数据范围也是挺明显的(2log_2a)。
考虑(y = x mod a,x in N+)的函数图像,现在要找到第一个零点,倍增找范围的正确性不是很明显,但是可以证明,分类讨论一下就行了.倍增找出的范围的图像是两段斜线且第一段斜线的最低点高于第二段斜线的最高点。
然后这个二分有点奇怪,写法需要莫名其妙一点。
时间复杂度(O(log_2 a)),两倍常数。
#include<bits/stdc++.h>
template<class T>T read()
{
T data=0,w=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') w=-1;
ch=getchar();
}
while(isdigit(ch))
data=data*10+ch-'0';
return data*w;
}
template<class T>T read(T&x)
{
return x=read<T>();
}
typedef long long ll;
using namespace std;
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
string cmd;
while(cin>>cmd)
{
if(cmd=="end")
break;
assert(cmd=="start");
int L=0,R=1;
while(1)
{
printf("? %d %d
",L,R);
fflush(stdout);
cin>>cmd;
if(cmd=="x")
break;
L=R,R*=2;
}
while(L+1<R)
{
// cerr<<"L="<<L<<" R="<<R<<endl;
int M=(L+R+1)/2;
assert(L<M);
printf("? %d %d
",L,M);
fflush(stdout);
cin>>cmd;
if(cmd=="x") R=M;
else L=M;
}
printf("! %d
",R);
fflush(stdout);
}
return 0;
}