CF1028G Guess the number 解题报告
包含本题的交互题单。
这个也是模板题吧。
首先题目很明显就是让我们找一个划分决策树的策略。
但是和二分、三分不同,这次我们可以划分的份数直接受到区间的 \(l\) 的影响,这使得直接数学构造非常麻烦。
我会 DP!设 \(f[l][r]\) 代表在 \([l,r]\) 这个区间中完成游戏所需要的最少操作次数,但是显然数据太大。
然后就是不难发现 \(1 \le k \le 10^4\),直接这样描述状态太浪费了。先把第一维改成目前可以询问的最长数组长度。
想了想发现直接把第二维改成目前剩余的询问机会比较好,这样就可以 DP 了,转移是显然的。
然后我们发现直接 DP 是 \(\mathcal{O}(k^2)\),这不好。但是又不难发现,可以剪枝,DP 代码如下。
const int N = 1e4 + 7;
int f[N][7];
int dfs(int l, int ch){
if(ch == 0) return f[l][ch] = 0;
if(f[l][ch] != -1) return f[l][ch];
int cur = min(l, 10000ll);
int res = dfs(cur, ch - 1);
f[l][ch] = res;
cur = min(10000ll, l + res + 1);
for(int i = 1; i <= l; i ++){
res = dfs(cur, ch - 1);
if(cur >= 10000){
f[l][ch] += (res + 1) * (l - i + 1);
break;
}
f[l][ch] += res + 1;
cur = min(10000ll, cur + res + 1);
}
return f[l][ch];
}
然后就跑得飞快了。
然后询问就是模仿转移就可以了,对于有的题可以直接把转移的状态存下来,这题就不必了。
signed main(){
ios::sync_with_stdio(0), cin.tie(0);
memset(f, -1, sizeof f);
dfs(1, 5);
int L = 1, R = 10004205361450474;
for(int ch = 5; ch; ch --){
vector<int> qur;
int l = L;
l += f[min(10000ll, l)][ch - 1];
l --;
while(l < R){
qur.push_back(++ l);
l += f[min(10000ll, l + 1)][ch - 1];
}
int k = qur.size();
cout << k << " ";
for(int x: qur) cout << x << " ";
cout << endl;
int res; cin >> res;
if(res == -1 || res == -2) return 0;
else{
if(res == 0) R = qur[0] - 1;
else if(res == k) L = qur.back() + 1;
else L = qur[res - 1] + 1, R = qur[res] - 1;
}
}
return 0;
}

浙公网安备 33010602011771号