1 条题解
-
0
自动搬运
来自洛谷,原作者为

Suzt_ilymtics
公主与玫瑰,随时待骑士归来 | AFO | SDUer搬运于
2025-08-24 22:28:46,当前版本为作者最后更新于2021-08-21 08:40:29,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
写在前面
感谢 @zimujunqwq 的思路。
Description
题目描述。
不知如何简化题意。Solution
Subtask1
考虑用询问 把 的元素位置确定,那么剩下的 的两个位置也能确定。
注意我们暂时还不能区分他们。
此时利用询问 ,询问 两个位置对 两个位置取模的结果。
他们的结果是不同的,所以可以确定出 对应的位置了。
期望得分 。
Subtask2
通过观察数据范围发现 。
所以注定这是一个 算法。
我们可以利用 操作询问 次。把 从 不断下调,即每次询问 都比上一次小 。
这样每次询问我们都会多知道一个元素的位置,而这个元素的值也是确定的。
期望得分 。
Subtask3,4,5
反正我没看出 Subtask3,4 有什么单独的做法,有卡到这一档的可以单独和我说一声qwq。
注意到后面的数据 ,所以我们可能每次询问 都要确定出一个位置。
现在假设我们知道了 的位置,那么不难发现, 这些数对 取模的值是互不相同的。这就启发我们可以先确定出 的位置,然后通过几次询问确定他后面的数的位置。
注意模数为 时要特判一下。这样的话,问题的规模就会缩小一半。
我们就可以继续处理剩下一半的情况。
如何确定 的位置?
可以询问两次询问 。第一次求出 的所有位置,第二次求出 的所有位置,那么新增加的位置就是 。
我们可以发现,这样递归处理需要 次,并且数据范围是 。
期望得分 。
Subtask6
观察数据发现 。
那就是说只让我们进行 次询问。
我们考虑通过询问 把 的位置求出来。我们想知道他的位置可以通过知道 的位置求出来。然后我们不断这样递归下去,发现我们只要知道了 的位置,并且知道了各个段的位置,就可以回溯到整个序列。而 的位置会在最后我们通过询问 询问 的时候求出。
这样的话,我们就可以在 次询问 内求出所有位置。
期望得分 。
Subtask7
这个之后我们发现 。
怎么压缩这两次询问?
通过自己手模每次询问的位置发现最后几个询问是 ,我们考虑把前两个询问去掉。
最后询问 的时候,我们得到的两个位置一定是 ,未知的两个位置是 。
这是什么?Subtask1 啊!
然后这题就做完了。
需要注意的一点是,Subtask3,4 的数据下,最后几次询问的位置是 ,也就是说 没有被划分到一段内。这个情况更好处理 因为我们知道了 的位置。
我们要爱惜自己的询问次数,因为 ,不能浪费,所以确定出前几个数后,再求其他数的时候要从已经确定的数的下一个开始求。
代码实现
我用 按照第几次询问标记了每个段的颜色,然后利用一个 数组将颜色从大到小排序,这样每段颜色都被放在了一起,颜色相同的段在值域上也是连续的,就可以 的求出整个序列了。
实现细节参考代码吧。
Code
/* Work by: Suzt_ilymics Problem: 不知名屑题 Knowledge: 垃圾算法 Time: O(能过) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #define LL long long #define orz cout<<"lkp AK IOI!"<<endl using namespace std; const int MAXN = 1e5+5; const int INF = 1e9+7; const int mod = 1e9+7; int n, m1, m2, m3; int a, b, x, y, mod1, mod2; int ans[MAXN]; int vis[MAXN], c[MAXN]; int stc[MAXN], sc = 0; int read(){ int s = 0, f = 0; char ch = getchar(); while(!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return f ? -s : s; } namespace Subtask1 { void Solve() { printf("? 4 1 2 3 4 3\n"); fflush(stdout); int k = read(); x = read(), y = read(); for(int i = 1; i <= 4; ++i) if(i != x && i != y) a = i; for(int i = 1; i <= 4; ++i) if(i != x && i != y && i != a) b = i; printf("! %d %d\n", x, a); fflush(stdout); mod1 = read(); printf("! %d %d\n", x, b); fflush(stdout); mod2 = read(); if(mod1 + mod2 == 0) { ans[x] = 4, ans[y] = 3; } else { ans[x] = 3, ans[y] = 4; if(mod1 == 1) { ans[a] = 2, ans[b] = 1; } else { ans[b] = 2, ans[a] = 1; } printf("A %d %d %d %d\n", ans[1], ans[2], ans[3], ans[4]); fflush(stdout); return ; } printf("! %d %d\n", y, a); fflush(stdout); mod1 = read(); printf("! %d %d\n", y, b); fflush(stdout); mod2 = read(); if(mod1 == 1) { ans[a] = 2, ans[b] = 1; } else { ans[b] = 2, ans[a] = 1; } printf("A %d %d %d %d\n", ans[1], ans[2], ans[3], ans[4]); fflush(stdout); return ; } } namespace Subtask2 { void Solve() { for(int i = n; i >= 1; --i) { printf("? %d ", n); for(int j = 1; j <= n; ++j) printf("%d ", j); printf("%d\n", i); fflush(stdout); int k = read(); for(int j = 1, x; j <= k; ++j) { x = read(); if(vis[x]) continue; vis[x] = true; ans[x] = i; } } printf("A"); for(int i = 1; i <= n; ++i) { printf(" %d", ans[i]); } puts(""); fflush(stdout); } } bool cmp(int x, int y) { return vis[x] > vis[y]; } void Divide(int l, int r, int col) { int mid = (r + 1) / 2 + 1; if(mid == 2) { for(int i = 1; i <= n; ++i) if(!vis[i]) vis[i] = col; sort(c + 1, c + n + 1, cmp); return ; } sc = 0; for(int i = 1; i <= n; ++i) { if(!vis[i]) stc[++sc] = i; } printf("? %d ", sc); for(int i = 1; i <= sc; ++i) printf("%d ", stc[i]); printf("%d\n", mid); fflush(stdout); int k = read(); for(int i = 1, x; i <= k; ++i) { x = read(); vis[x] = col; } Divide(l, mid - 1, col + 1); } int main() { n = read(), m1 = read(), m2 = read(), m3 = read(); if(n == 4) { Subtask1::Solve(); } else if(n == 500){ Subtask2::Solve(); } else { for(int i = 1; i <= n; ++i) c[i] = i; Divide(1, n, 1); // for(int i = 1; i <= n; ++i) cout<<vis[i]<<" "; puts(""); // for(int i = 1; i <= n; ++i) cout<<c[i]<<" "; puts(""); int Max, lst, wz; if(vis[c[3]] != vis[c[4]]) { printf("! %d %d\n", c[3], c[1]); fflush(stdout); int mod1 = read(); printf("! %d %d\n", c[3], c[2]); fflush(stdout); int mod2 = read(); ans[c[3]] = 3; if(mod1 == 1) ans[c[1]] = 2, ans[c[2]] = 1; else ans[c[1]] = 1, ans[c[2]] = 2; Max = 3, lst = wz = c[3]; } else { printf("! %d %d\n", c[3], c[1]); fflush(stdout); int mod1 = read(); printf("! %d %d\n", c[3], c[2]); fflush(stdout); int mod2 = read(); if(mod1 + mod2 == 0) { ans[c[3]] = 4, ans[c[4]] = 3; printf("! %d %d\n", c[4], c[1]); fflush(stdout); mod1 = read(); if(mod1 == 1) ans[c[1]] = 2, ans[c[2]] = 1; else ans[c[1]] = 1, ans[c[2]] = 2; } else { ans[c[3]] = 3, ans[c[4]] = 4; if(mod1 == 1) ans[c[1]] = 2, ans[c[2]] = 1; else ans[c[1]] = 1, ans[c[2]] = 2; } Max = 4, lst = wz = (ans[c[4]] == 4 ? c[4] : c[3]); } for(int i = ((vis[c[3]] == vis[c[4]]) ? 5 : 4); i <= n; ++i) { if(vis[c[i]] != vis[c[i - 1]]) { lst = wz; // 上一个颜色 Max = 0, wz = 0; // 新的颜色 } printf("! %d %d\n", c[i], lst); fflush(stdout); int x = read(); if(x) { ans[c[i]] = ans[lst] + x; } else { ans[c[i]] = ans[lst] * 2; } if(Max < ans[c[i]]) { Max = ans[c[i]]; wz = c[i]; } } printf("A"); for(int i = 1; i <= n; ++i) { printf(" %d", ans[i]); } puts(""); fflush(stdout); } return 0; }
- 1
信息
- ID
- 6798
- 时间
- 1000ms
- 内存
- 500MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者