#include<bits/stdc++.h> usingnamespace std; #define ll long long constint INF = 0x3f3f3f3f; const ll inf = 0x3f3f3f3f3f3f3f3f; constint N = 2e5 + 10; const ll mod = 1e9 + 7; int T; int a[N], b[N], n; typedef pair<int, int>pii; vector<pii>va, vb; boolck(){ int n = (int)va.size(); for (int i = 0; i < n; i++) { if (va[i] != vb[i])returnfalse; } returntrue; } intmain(){ scanf("%d", &T); while (T--) { scanf("%d", &n); va.clear(); vb.clear(); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for (int i = 1; i <= n; i++)scanf("%d", &b[i]); for (int i = 1; i <= (n + 1) / 2; i++) { int x = min(a[i], a[n - i + 1]), y = max(a[i], a[n - i + 1]); va.push_back(pii(x, y)); x = min(b[i], b[n - i + 1]), y = max(b[i], b[n - i + 1]); vb.push_back(pii(x, y)); } sort(va.begin(), va.end()); sort(vb.begin(), vb.end()); if (!ck())puts("No"); elseputs("Yes"); } return0; }
G. Secure Password
题意:又是交互题。评测机有一个数列,问除了第 i 个数之外所有的数的或。每次询问可以得到询问的序列的或。1≤n≤1000,询问次数不超过13。
和上次题目很像,上次是最大值,这次是或。但是做法完全不同。这次并不能二分。
考虑下标。预先询问一些序列的或。对于下标 i ,需要用预先询问过的这些序列拼出覆盖除了 i 以外的所有下标,由于是或,所以重复了没关系。
对于下标 i ,如果有下标 j 的二进制是它的子集,由于下标都不相同,所以一定存在某一位在 i 中是1,而在 j 中是0;而如果下标 j 不是 i 的子集,则一定有某一位在 j 中是1,而在 i 中是0。
所以预先对于每一个二进制位,询问在这一位是0的所有数的或,询问在这一位是1的所有下标的或。再对每个下标 i ,遍历它的二进制位,如果该位是1,则答案或上该位是0的询问结果;如果该位是0,则答案或上该位是1的询问结果,这样一定能覆盖到所有除了 i 以外的下标。并且一定不包含 i 。
但是这样询问次数为 2log,还是不行。
询问这一位是1的所有下标的或仅仅是由于下标 j 的二进制可能是 i 的子集,之前把下标自身作为id,而如果重新给每个下标分配一个id,且保证不存在有包含关系的id,不就可以去掉这种情况了?