最逆天的一集。
ARC184 A
题目解析
切入点 1:注意到 \(m\) 很小,只有 \(10\),并且 \(q = 950\)。考虑有什么性质。
我们发现 \(m\) 很小,我们考虑挖掘性质。
有一个关键观察:如果有大于 \(10\) 个数的类型相等,那么他们一定都是好的。
如果我们知道了 \(20\) 个数中的相对情况,假设有 \(x\) 个数类型相等,其他 \(n - x\) 个数类型相等,这两种数类型不同,由于上面的性质,当 \(x \neq 10\) 时,数量较多的一类必定是好数,数量较少的一类必定是坏数。
按照上面的启发,我们考虑将 \(1000\) 个数进行分组,每组内有 \(20\) 个数。我们计算这 \(20\) 个数的相对情况(这是容易的),然后根据上面的结论,我们就能知道当一组内两种类型数目不相等时它们的好坏之分。
因此,我们只需要考虑 \(x = 10\) 的情况(这种组别显然最多只有一个)。这好办,我们只需要将在这组内的任意一个数和不在这组内的任意一个数比较,这样我们就能区分出哪一种类别是好数。
需要注意一个细节:这样算下来最多的询问次数会到达 \(951\),所以需要轻微的调整来解决这一问题。具体比较简单,可以看代码。
void solve() {cin >> n >> m >> q;vector <int> ans;for (int i = 1; i <= 50; i ++) {int l = (i - 1) * 20 + 1, pos = 0, cnt0 = 1, cnt1 = 0;int tar = -1;for (int j = 2; j <= 20 && (i != 50 || !ans.empty()); j ++) {cout << "? " << l << ' ' << l + j - 1 << endl;cin >> col[l + j - 1];cnt0 += (col[l + j - 1] == 0);cnt1 += (col[l + j - 1] == 1);}if (i == 50 && ans.empty()) {for (int j = 1; j <= 19; j ++) {cout << "? " << 1 << ' ' << j + l - 1 << endl;cin >> col[j + l - 1];cnt0 += (col[l + j - 1] == 0);cnt1 += (col[l + j - 1] == 1);if (col[j + l - 1] == 1) ans.push_back(j + l - 1);}if (cnt1 == 9)ans.push_back(1000);break;}if (cnt0 < cnt1) {for (int j = 1; j <= 20; j ++)if (col[l + j - 1] == 0) ans.push_back(l + j - 1);} else if (cnt0 > cnt1) {for (int j = 1; j <= 20; j ++)if (col[l + j - 1] == 1) ans.push_back(l + j - 1);} else {pos = (i == 1 ? 1000 : 1);cout << "? " << l << ' ' << pos << endl;cin >> tar;tar ^= 1;for (int j = 1; j <= 20; j ++)if (col[l + j - 1] == tar) ans.push_back(l + j - 1);break;}}cout << "! ";for (int x : ans) cout << x << ' ';cout << endl;
}