$\texttt{Subtask # 1}$ 我们直接手动模拟。首先肯定要进行一次 ? l S p 操作求得 $4$ 的位置。然后发现 $1$ 至 $3$ 中只有 $3$ 除 $4$ 无法整除,这样我们就可以通过 ! x y 操作求得 $3$ 的位置。同理求出 $2$ 的位置,则最后剩下的一个位置就是 $1$ 了。

$\texttt{Subtask # 2-3}$ $m_2$ 很大,所以我们可以只用 ? l S p 操作每次求出 $[1,n]$ 间的最大值,然后不断缩小区间直至 $[1,1]$。

$\texttt{Subtask # 4-6}$ 看到 $m_2$ 的值在 $20$ 以内,便能猜想复杂度与 $2$ 的幂次有关。计算了一下 $2^{15}$ 与 $5 \times 10^4$ 大致接近,故再次联想到二分。于是乎,就有了二分答案的做法。

对于 ! x y 操作,因为一定要保证询问合法,所以一定是建立在排列上的某位已经确定的情况下。那么肯定需要先从 ? l S p 操作中获取一个数以开始询问。我们想要求出 $[1,n]$ 内的排列,可以先用 ? l S p 操作获取 $n$ 的位置,然后可以根据 $n \bmod (\frac{n}{2},n)$ ,其中余数互部不重复的性质用 ! x y 操作求解出 $(\frac{n}{2},n)$ 内所有数的位置。然后继续减半重复操作直到 $n = 1$ 后把最后一个剩下的位置标记为 $1$ 即可。需要注意的是由于 $m_3$ 的限制,所以 ? l S p 操作时的 $l$ 的大小应该为还未被确定的数的个数,而不是草率的赋值为排列的大小。

$\texttt{Subtask # 7}$ 但是由于一开始的 ? l S p 操作,经过计算发现此时代码无法通过最后一个子任务。最简单的方式就是在最后一次二分时特判以减少一次 ? l S p 操作。最后一次二分操作是在 $[1,2]$ 或 $[1,3]$ 的范围时,但因为题中 $n$ 的大小已经确定,所以计算得出只需要特判后者的情况即可。我们仍然用第一个操作中余数互不相同以求出区间中不同的数的性质,发现 $5 \bmod i (1 \le i \le 3)$,恰好余数互不相同,故最少使用两次 ! x y 操作代替原来的 ? l S p 操作求出。

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <iostream>
#include <vector>
using namespace std;
const int MAX = 5e4 + 50;
vector <int> v;
int n,a,b,c,x,y,bg;
int num[MAX];
void work (int r,int mo);
int main ()
{
cin>>n>>a>>b>>c;
if (n == 4)
{
cout<<"? 4 1 2 3 4 4"<<endl;cout.flush();
cin>>x>>y;num[y] = 4;
for (int i = 1;i <= 4;++i)
{
if (num[i]) continue;
cout<<"! "<<y<<" "<<i<<endl;cout.flush();
cin>>x;
if (x != 0)
{
num[i] = 3,y = i;
break;
}
}
for (int i = 1;i <= 4;++i)
{
if (num[i]) continue;
cout<<"! "<<y<<" "<<i<<endl;cout.flush();
cin>>x;
if (x != 0) num[i] = 2,y = 1;
else num[i] = 1,y = 2;
break;
}
for (int i = 1;i <= 4;++i)
{
if (num[i]) continue;
num[i] = y;
}
cout<<"A ";
for (int i = 1;i <= 4;++i) cout<<num[i]<<" ";
cout<<endl;cout.flush ();
return 0;
}
cout<<"? "<<n<<" ";
for (int i = 1;i <= n;++i) cout<<i<<" ";
cout<<n<<endl;cout.flush ();
cin>>x>>y;
num[y] = n;
work (n - 1,y);
cout<<"A ";
for (int i = 1;i <= n;++i) cout<<num[i]<<" ";
cout<<endl;cout.flush ();
return 0;
}
void work (int r,int mo)
{
if (r == 1)
{
for (int i = 1;i <= n;++i)
if (!num[i]) num[i] = num[mo] - 1;
return ;
}
v.clear ();
if (r == 3)
{
for (int i = 1;i <= n;++i)
if (!num[i]) v.push_back (i);
for (int i = 1;i <= n;++i)
{
if (num[i] == 5)
{
bg = i;
break;
}
}
cout<<"! "<<bg<<" "<<v[0]<<endl;cout.flush ();
cin>>x;
if (x == 0) num[v[0]] = 1;
if (x == 1) num[v[0]] = 2;
if (x == 2) num[v[0]] = 3;
cout<<"! "<<bg<<" "<<v[1]<<endl;cout.flush ();
cin>>y;
if (y == 0)
{
num[v[1]] = 1;
if (x == 1) num[v[2]] = 3;
else num[v[2]] = 2;
}
if (y == 1)
{
num[v[1]] = 2;
if (x == 0) num[v[2]] = 3;
else num[v[2]] = 1;
}
if (y == 2)
{
num[v[1]] = 3;
if (x == 0) num[v[2]] = 2;
else num[v[2]] = 1;
}
return ;
}
int mid = r >> 1,cnt = 0;
for (int i = 1;i <= n;++i)
if (!num[i]) ++cnt;
cout<<"? "<<cnt<<" ";
for (int i = 1;i <= n;++i)
if (!num[i]) cout<<i<<" ";
cout<<mid + 1<<endl;cout.flush ();
cin>>x;
for (int i = 1;i <= x;++i)
{
cin>>y;
if (!num[y]) v.push_back (y);
}
for (int i = 0;i < v.size ();++i)
{
cout<<"! "<<mo<<" "<<v[i]<<endl;cout.flush ();
cin>>x;
if (x == 0)
{
num[v[i]] = num[mo] - (num[mo] >> 1);
if (mid + 1 == num[mo] - (num[mo] >> 1)) y = v[i];
}
else
{
num[v[i]] = num[mo] - x;
if (mid + 1 == num[mo] - x) y = v[i];
}
}
work (mid,y);
}