题解:P17216 [ICPC 2017 Nanning R] The Chosen One

· · 题解

前置知识

思路

首先注意到数非常大,所以需要使用高精度。

然后我们思考,每次删除人,没被删除的人的下标会变成什么,假设这个人的下标为 x,那么经过一次操作后下标就会变成 \frac{x}{2},又因为 x 为奇数的 x 肯定都被删光了,所以 \frac{x}{2} 肯定是正整数。

接着我们思考,什么数可以撑到最后,也就是能除以 2 最多的数,那么肯定是 \le n 的最大的二的次幂,所以我们统计二进制下的 n 一共有几位,这样就可以算出答案了。

```cpp void div2(){ int carry = 0; for(int i = p + 1;i <= len;i ++){ int num = carry * 10 + str[i] - '0'; str[i] = (num >> 1)+ '0'; carry = num & 1; } while(p < len and str[p + 1] == '0'){ p ++; } } ``` 答案的高精度: ```cpp void mul2(){ int carry = 0; for(int i = anslen - 1;i >= 0;i --){ int num = (carry + (ans[i] - '0') * 2); ans[i] = (num % 10) + '0'; carry = num / 10; } while(carry > 0){ anslen ++; ans = (char)((carry % 10) + '0') + ans; carry /= 10; } } ``` 多测记得清空。 ### Code ```cpp #include<bits/stdc++.h> using namespace std; int Q,len,p,anslen; string str,ans; void div2(){ int carry = 0; for(int i = p + 1;i <= len;i ++){ int num = carry * 10 + str[i] - '0'; str[i] = (num >> 1)+ '0'; carry = num & 1; } while(p < len and str[p + 1] == '0'){ p ++; } } void mul2(){ int carry = 0; for(int i = anslen - 1;i >= 0;i --){ int num = (carry + (ans[i] - '0') * 2); ans[i] = (num % 10) + '0'; carry = num / 10; } while(carry > 0){ anslen ++; ans = (char)((carry % 10) + '0') + ans; carry /= 10; } } int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> Q; while(Q --){ cin >> str; len = str.length(); str = " " + str; p = 0; ans = "1"; anslen = 1; while(p != len and (p < len - 1 or str[len] != '1')){ mul2(); div2(); } for(int i = 0;i < anslen;i ++){ cout << ans[i]; } cout << "\n"; } return 0; } ```