E. Guess the Cycle Size
前置知识点:C/C++交互,概率论
题意:有 nnn 个点组成的环,点的编号从 1−n1 - n1−n ,要求在只能询问 505050 次的清况下,预测出 nnn 的具体值是多少,nnn 的范围 (3≤n≤1018)(3\leq n \leq 10^{18})(3≤n≤1018) 。
利用 ? a b?\ a\ b? a b 询问两点之间的距离,由于是一个环形,所以会有两条路径,系统为以相同的概率给出其中的一条路径长度。在询问 ? a b?\ a\ b? a b 和 ? b a?\ b \ a? b a 时,输出的答案可能不同。
最后将结果以 ! n!\ n! n 的形式输出。
菜鸡思路:刚开始看到这个题目就会感觉这里只需要查看点是否在环上就可以了,如果询问的点不在环上,那么系统会输出 −1-1−1,所以紧扣这一点,我们能用二分求解问题,但是,这里只有 505050 次的询问机会,如果使用二分求解,那会需要 log21018>50log_{2}^{10^{18}} > 50log21018>50 次,所以二分的求解不太可行。
如果直接用 101810^{18}1018 的值,那连样例都过不了,所以我们可以把数据变换一下,变成 101410^{14}1014 看看结果
官方题解:先查询 (1,n)(1,n)(1,n) 值 ,如果第一次查询我们得到的答案就是 −1-1−1 ,那环的大小就是 n−1n-1n−1 ,否则 ,那我们再查询 (n,1)(n,1)(n,1) 的值,如果两次的答案相同,那 nnn 加 111 循环上面的操作,如果两次的结果不相同,那环的大小就是两个答案相加。
两条路径长度分别用 x、yx、yx、y 表示,xxx 和 yyy 出现的概率相同 (12)(\frac{1}{2})(21) ,252525 次查询出现不同的值的概率为 1−(12)25≈0.999999971 - (\frac{1}{2})^{25} \approx 0.999999971−(21)25≈0.99999997
#include <stdio.h>
#include <algorithm>
using namespace std;
typedef long long ll;
int main(){
ll k1 = 0,k2 = 0,k = 0;
ll l = 1,r = 4;
int L = 25;
while(L --) {
printf("? %lld %lld\n",l,r);
fflush(stdout);
scanf("%lld",&k1);
printf("? %lld %lld\n",r,l);
fflush(stdout);
scanf("%lld",&k2);
if(k1 != k2) {
k = k1 + k2;
break;
}
else if(k1 == -1) {
k = r - 1;
break;
}
r ++;
}
printf("! %lld\n",k);
fflush(stdout);
return 0;
}