D. Game with modulo 交互题
题目大意:
题目:未知一个数 \(a\),让你每次猜两个数 \(x\) 和$ y$,若 \((x\bmod a)\ge (y\bmod a)\) 返回 x,否则返回 y。让你猜测次数少于60次的时候猜出数 \(a\)。
题解:
交互题,这个算是我最不会写也不太想写的题目之一了。
还是有点难的,接下来说说我看了这么多的博客之后的想法。

首先很容易的发现这个就是一个周期为a的函数,图像如上。
所以每次找 \(i\) ,如果 \(i*2\bmod\,a <=i\bmod\,a\) ,那么显然易见,在区间 \([i,i*2]\) 有且仅有一个值 $x\bmod,a = 0 $ ,那么从小到大找到的第一个 \(x\),这个 \(x=a\)。
接下来贴一下证明:https://www.cnblogs.com/ttttttttrx/p/10800618.html

好像不是那么容易理解,接下来我简单说说。
- \(a\bmod \,b<a/2(a>=b)\) ,\(a-b*k=x\)
- 其中 \(b*k>=a/2\) ,应该可以缩小成 \(b*k>a/2\),这个是因为如果\(b*k<=a/2\) ,那么 \(2*b*k<=a\),所以 \(b*k>a/ 2\), 所以 \(x<a/2\)
- 所以 \(a\bmod\,b<a/2(a>=b)\)
- 如果 \(a<b\) ,那么 \(a\bmod \,b<a/2(a>=b)\) 一定不成立,因为 \(a\bmod\,b=a>a/2\)
- 综上所述,从小到大找,找到的第一个 \(i*2\bmod\,a <=i\bmod\,a\) ,那么 \(a\) 一定在区间 \([i,2*i]\) 之间
- 最后说说为什么是每次找 \([2^i,2^{i+1}]\) ,因为如果 \([2^{i-1},2^i]\) 没有找到,说明 \(2^i<a\) 那么 区间 \([2^i,2^{i+1}]\) 一定最多一个点 \(x\),使得 \(x\bmod\,a=0\)
所以说,如果找到了一个 \(i*2\bmod\,a <=i\bmod\,a\) ,那么 \(i*2>a\) 一定成立。
这个之后就是一个二分,这个二分比较特别,因为我已经知道 \(i\bmod\,a>i*2\bmod\,a\) ,并且 \(2*i>a \& i<a\) ,所以我每次枚举 \([mid,r]\)
如果结果是 \(r\),那么说明已经应该是 \(r\) 变小,如果结果是 \(mid\) 那么说明 \(l\) 可以变大,自行领悟吧。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3+10;
typedef long long ll;
char s[10];
int main(){
    while(true){
        scanf("%s",s+1);
        if(s[1]=='s'){
            ll l = 0,r = 1;
            for(int i=1;i<=35;i++){
                printf("? %lld %lld\n",l,r);
                fflush(stdout);
                scanf("%s",s+1);
                if(s[1]=='x') break;
                //如果等于x,表示i mod a > i*2 mod a 
                l = r,r <<= 1;
            }
            ll ans=0;
            while(l<=r){
                ll mid=(l+r)>>1;
                printf("? %lld %lld\n",mid,r);
                fflush(stdout);
                scanf("%s",s+1);
                if(mid+1==r){
                    if(s[1]=='x') ans = r;
                    //如果 mid mod a > r mod a,因为答案ans一定是 ans%a = 0,所以更小的这个应该是答案
                    else ans = mid;
                    break;
                }
                else if(s[1]=='x') l = mid;
                else r = mid;
            }
            printf("! %lld\n",ans);
            fflush(stdout);
        }
        else break;
    }
    return 0;
}
/*
input
start
x
x
start
x
x
y
start
x
x
y
y
end
output
? 0 0
? 10 1
! 1
? 0 0
? 3 4
? 2 5
! 2
? 2 4
? 2 5
? 3 10
? 9 1
! 3
 */
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号