EOJ Monthly 2018.11 猜价格 (模拟)
分三种情况:
1.k=1。此时每次都说反话,反着二分即可。
2.1<k <= n。那么在前n次问答中一定会出现一次错误,通过不断输出1找出那个错误发生的位置(若回答是>那这就是错误)。此后每隔k次就会有一个错误发生,判断出来即可。
3.k > n。不能用上面的方式,否则回答次数会超过2n。因为k>n,所以在2n次问答中只会出现一个错误,所以通过每次输出两个同样的数,判断是否出现错误。当两次得到应答不一致时,就说明错误发生,再输出一个同样的数确定是非。此外便可以正常二分。
*清空缓冲区要用cin
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
typedef long long LL;
LL n,k;
void gao1()
{
LL mid,L= 1, R= ((1LL)<<n)-1;
char c;
while(L<=R){
mid = L+(R-L)/2;
printf("%lld\n",mid);
cin>>c;
if(c== '=' ){
break;
}
else if(c== '<' ){
R = mid-1;
}
else{
L = mid+1;
}
}
}
void gao2()
{
int pos;
char c;
for(int i=1;i<=n;++i){
printf("1\n");
cin>>c;
if(c=='>'){
break;
}
}
LL mid,L= 1, R= ((1LL)<<n)-1;
int cnt = 1;
while(L<=R){
mid = L+(R-L)/2;
printf("%lld\n",mid);
cin>>c;
if(c=='=')
break;
else if(c=='<'){
if(cnt==k){
cnt = 0;
R = mid-1;
}
else L = mid+1;
}
else{
if(cnt==k){
cnt = 0;
L = mid+1;
}
else{
R = mid-1;
}
}
cnt++;
}
}
void gao3()
{
LL mid,L= 1, R= ((1LL)<<n)-1;
char c1,c2;
bool flag = true;
while(L <= R ){
mid = L+(R-L)/2;
printf("%lld\n",mid);
cin>>c1;
if(c1=='=')
break;
if(flag){
printf("%lld\n",mid);
cin>>c2;
if(c2=='=')
break;
if(c1!=c2){ //error
flag = false;
char c3;
printf("%lld\n",mid);
cin>>c3;
if(c1==c3){
if(c1=='<') L = mid+1;
else R = mid-1;
}
else{
if(c2=='<') L = mid+1;
else R = mid-1;
}
}
else{
if(c1=='<') L = mid+1;
else R = mid-1;
}
}
else{
if(c1=='<') L = mid + 1;
else R = mid - 1;
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int in;
scanf("%lld %lld",&n, &k);
if(n==1){
printf("1\n");
return 0;
}
if(k==1) gao1();
else if(k<=n) gao2();
else gao3();
return 0;
}
为了更好的明天