C. Chocolate Bunny
time limit per test: 1 second
memory limit per test: 256 megabytes
input: standard input
output: standard output
This is an interactive problem.
We hid from you a permutation p p p of length n n n, consisting of the elements from 1 1 1 to n n n. You want to guess it. To do that, you can give us 2 different indices i i i and j j j, and we will reply with p i m o d p j p_i \ mod \ p_j pi mod pj(remainder of division p i p_i pi by p j p_j pj).
We have enough patience to answer at most 2 ⋅ n 2⋅n 2⋅n queries, so you should fit in this constraint. Can you do it?
As a reminder, a permutation of length n n n is an array consisting of n n n distinct integers from 1 1 1 to n n n in arbitrary order. For example, [ 2 , 3 , 1 , 5 , 4 ] [2,3,1,5,4] [2,3,1,5,4] is a permutation, but [ 1 , 2 , 2 ] [1,2,2] [1,2,2] is not a permutation ( 2 2 2 appears twice in the array) and [ 1 , 3 , 4 ] [1,3,4] [1,3,4] is also not a permutation ( n = 3 n=3 n=3 but there is 4 4 4 in the array).
Input
The only line of the input contains a single integer n ( 1 ≤ n ≤ 1 0 4 ) n(1\leq n \leq 10^4) n(1≤n≤104) — length of the permutation.
Interaction
The interaction starts with reading n n n.
Then you are allowed to make at most 2 ⋅ n 2⋅n 2⋅n queries in the following way:
- “? x y” ( 1 ≤ x , y ≤ n , x ≠ y ) (1≤x,y≤n,x≠y) (1≤x,y≤n,x=y).
After each one, you should read an integer k k k, that equals p x m o d p y p_x\ mod\ p_y px mod py.
When you have guessed the permutation, print a single line "! " (without quotes), followed by array p p p and quit.
After printing a query do not forget to output end of line and flush the output. Otherwise, you will get Idleness limit exceeded. To do this, use:
- fflush(stdout) or cout.flush() in C++;
- System.out.flush() in Java;
- flush(output) in Pascal;
- stdout.flush() in Python;
- see documentation for other languages.
Exit immediately after receiving “-1” and you will see Wrong answer verdict. Otherwise you can get an arbitrary verdict because your solution will continue to read from a closed stream.
Hack format
In the first line output n ( 1 ≤ n ≤ 1 0 4 ) n(1\leq n \leq 10^4) n(1≤n≤104). In the second line print the permutation of n n n integers p 1 , p 2 , . . . , p n p_1, p_2, ..., p_n p1,p2,...,pn.
Example
input
3
1
2
1
0
output
? 1 2
? 3 2
? 1 3
? 2 1
! 1 3 2
题目大意
给定整数n,让你猜出一个1到n的排列
猜的过程可以进行至多2*n次提问,提问的格式为? x y,将会返回第x个元素对第y个元素取模的结果
最后以! 开头,输出这个排列
解法
其实 2 ∗ n 2*n 2∗n次提问推导 n n n个元素,容易想到(容易吗?),使用2次提问就可以推导出1个元素。
怎么推导呢?
假设这两个数是 x x x和 y y y,且 x < y x<y x<y
那么两次提问将会得到两个结果:
- m o d 1 = x m o d y mod1 = x \ mod \ y mod1=x mod y
- m o d 2 = y m o d x mod2 = y \ mod \ x mod2=y mod x
由于假设 x < y x<y x<y,显然有 m o d 1 = x mod1=x mod1=x,而 m o d 2 mod2 mod2是对 x x x取模,由模运算的特点可知 m o d 2 < x mod2<x mod2<x恒成立,也就有
- m o d 2 < x = m o d 1 mod2<x=mod1 mod2<x=mod1
也就有了这样的结论:
-
如果 m o d 2 < m o d 1 mod2<mod1 mod2<mod1,那么 m o d 1 = x mod1=x mod1=x
-
类似的有:如果 m o d 1 < m o d 2 mod1<mod2 mod1<mod2,那么 m o d 2 = y mod2=y mod2=y
因此只要每次取出两个未知元素,让他们互相对对方取模,就能得到一个元素的值,进行2*n次这样的询问就能得到n个元素的值
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4 + 5;
int a[maxn];
int q[maxn<<1], head, tail;
int main() {
int n; cin>>n;
head = tail = 0;
for(int i = 0; i < n; ++i)
q[tail++] = i;
int last = n * (n+1) / 2;
while(head < tail-1) {
int x = q[head++];
int y = q[head++];
cout<<"? "<<x+1<<" "<<y+1<<endl;
cout<<"? "<<y+1<<" "<<x+1<<endl;
int mod1, mod2; cin>>mod1>>mod2;
if(mod1 < mod2) {
q[tail++] = x;
a[y] = mod2;
last -= mod2;
}
else {
q[tail++] = y;
a[x] = mod1;
last -= mod1;
}
}
a[q[head]] = last;
cout<<"!";
for(int i = 0; i < n; ++i)
cout<<" "<<a[i];
cout<<endl;
cout.flush();
return 0;
}