P7843 「PMOI-4」猜排列 题解
Suzt_ilymtics · · 题解
写在前面
更好的阅读体验?
感谢 @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;
}