本文主要是介绍CodeforcesRound#749(Div.1.2basedonTechnocup2022EliminationRound1)-D.Omkar and the Meaning of Life-题解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
- Codeforces Round #749 (Div. 1 + Div. 2, based on Technocup 2022 Elimination Round 1) - D. Omkar and the Meaning of Life
- Problem Description
- Interaction
- Hack Format
- Sample Input
- Sample Onput
- Note
- 题目大意
- 解题思路
- AC代码
Codeforces Round #749 (Div. 1 + Div. 2, based on Technocup 2022 Elimination Round 1) - D. Omkar and the Meaning of Life
传送门
Time Limit: 2 seconds
Memory Limit: 256 megabytes
Problem Description
It turns out that the meaning of life is a permutation p 1 , p 2 , … , p n p1,p2,…,pn p1,p2,…,pn of the integers 1 , 2 , … , n ( 2 ≤ n ≤ 100 ) 1,2,…,n (2≤n≤100) 1,2,…,n(2≤n≤100). Omkar, having created all life, knows this permutation, and will allow you to figure it out using some queries.
A query consists of an array a 1 , a 2 , … , a n a1,a2,…,an a1,a2,…,an of integers between 1 1 1 and n n n. a is not required to be a permutation. Omkar will first compute the pairwise sum of a a a and p p p, meaning that he will compute an array s s s where s j = p j + a j s_j=p_j+a_j sj=pj+aj for all j = 1 , 2 , … , n j=1,2,…,n j=1,2,…,n. Then, he will find the smallest index k k k such that sk occurs more than once in s s s, and answer with k k k. If there is no such index k k k, then he will answer with 0 0 0.
You can perform at most 2 n 2n 2n queries. Figure out the meaning of life p p p.
Interaction
Start the interaction by reading single integer n ( 2 ≤ n ≤ 100 ) n (2≤n≤100) n(2≤n≤100) — the length of the permutation p p p.
You can then make queries. A query consists of a single line “ ? a 1 a 2 … a n ?\ a_1\ a_2\ …\ a_n ? a1 a2 … an” ( 1 ≤ a j ≤ n ) (1≤a_j≤n) (1≤aj≤n).
The answer to each query will be a single integer k k k as described above ( 0 ≤ k ≤ n ) (0≤k≤n) (0≤k≤n).
After making 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.
To output your answer, print a single line “ ! a 1 a 2 … a n !\ a_1\ a_2\ …\ a_n ! a1 a2 … an” then terminate.
You can make at most 2 n 2n 2n queries. Outputting the answer does not count as a query.
Hack Format
To hack, first output a line containing n ( 2 ≤ n ≤ 100 ) n (2≤n≤100) n(2≤n≤100), then output another line containing the hidden permutation p 1 , p 2 , … , p n p_1,p_2,…,p_n p1,p2,…,pn of numbers from 1 1 1 to n n n.
Sample Input
5201
Sample Onput
? 4 4 2 3 2? 3 5 1 5 5? 5 2 4 3 1! 3 2 1 5 4
Note
In the sample, the hidden permutation p p p is [ 3 , 2 , 1 , 5 , 4 ] [3,2,1,5,4] [3,2,1,5,4]. Three queries were made.
The first query is a = [ 4 , 4 , 2 , 3 , 2 ] a=[4,4,2,3,2] a=[4,4,2,3,2]. This yields s = [ 3 + 4 , 2 + 4 , 1 + 2 , 5 + 3 , 4 + 2 ] = [ 7 , 6 , 3 , 8 , 6 ] s=[3+4,2+4,1+2,5+3,4+2]=[7,6,3,8,6] s=[3+4,2+4,1+2,5+3,4+2]=[7,6,3,8,6]. 6 6 6 is the only number that appears more than once, and it appears first at index 2 2 2, making the answer to the query 2 2 2.
The second query is a = [ 3 , 5 , 1 , 5 , 5 ] a=[3,5,1,5,5] a=[3,5,1,5,5]. This yields s = [ 3 + 3 , 2 + 5 , 1 + 1 , 5 + 5 , 4 + 5 ] = [ 6 , 7 , 2 , 10 , 9 ] s=[3+3,2+5,1+1,5+5,4+5]=[6,7,2,10,9] s=[3+3,2+5,1+1,5+5,4+5]=[6,7,2,10,9]. There are no numbers that appear more than once here, so the answer to the query is 0.
The third query is a = [ 5 , 2 , 4 , 3 , 1 ] a=[5,2,4,3,1] a=[5,2,4,3,1]. This yields s = [ 3 + 5 , 2 + 2 , 1 + 4 , 5 + 3 , 4 + 1 ] = [ 8 , 4 , 5 , 8 , 5 ] s=[3+5,2+2,1+4,5+3,4+1]=[8,4,5,8,5] s=[3+5,2+2,1+4,5+3,4+1]=[8,4,5,8,5]. 5 5 5 and 8 8 8 both occur more than once here. 5 5 5 first appears at index 3 3 3, while 8 8 8 first appears at index 1 1 1, and 1 < 3 1<3 1<3, making the answer to the query 1 1 1.
Note that the sample is only meant to provide an example of how the interaction works; it is not guaranteed that the above queries represent a correct strategy with which to determine the answer.
题目大意
给你一个 n n n,这组数据其实是隐藏了 n n n的一个全排列。你可以进行最多 2 n 2n 2n次询问,每次输入一个新的序列,让隐藏的序列一一对应临时加上这个新的序列,之后把有相同的值的元素中,最小的下标返回给你。
让你通过询问,得出隐藏的序列。
比如样例隐藏了序列 [ 3 , 2 , 1 , 5 , 4 ] [3,2,1,5,4] [3,2,1,5,4],你进行了一次询问并让隐藏序列一一对应地临时加上你给的序列 [ 4 , 4 , 2 , 3 , 2 ] [4,4,2,3,2] [4,4,2,3,2]. 那么相加产生的临时序列是 [ 3 + 4 , 2 + 4 , 1 + 2 , 5 + 3 , 4 + 2 ] = [ 7 , 6 , 3 , 8 , 6 ] [3+4,2+4,1+2,5+3,4+2]=[7,6,3,8,6] [3+4,2+4,1+2,5+3,4+2]=[7,6,3,8,6]. 6 6 6 不只一个,所有有相同值的元素集合是: [ 第 2 个 元 素 , 第 5 个 元 素 ] [第2个元素,第5个元素] [第2个元素,第5个元素],其中下标最小的是第二个元素,它的下标是 2 2 2。因此,你得到了询问的结果: 2 2 2。
解题思路
其实每次询问可以把其中一个数 a a a加一,其他所有数都加2。那么如果有 b = a − 1 b=a-1 b=a−1,那么因为 a a a 加了 1 1 1 而 b b b 加了 2 2 2 ,所以 a a a和 b b b加上临时序列后的值就会相同,因此就会返回这两个数中下标最小的元素。如果很荣幸 b = a − 1 b=a-1 b=a−1在 b b b的前面,那么我们就得到了比 a a a小 1 1 1的那个数的下标。
同理,只把 a a a加上 2 2 2,其他元素都加上 1 1 1,就可以令 a a a和 a + 1 a+1 a+1相等(如果存在的话)。如果 a + 1 a+1 a+1在 a a a的前面,那么我们就能得到比 a a a大 1 1 1的数的下标。
正好 2 ∗ n 2*n 2∗n次询问,我们可以得到 n − 1 n-1 n−1个“大1关系”,即得到了 n − 1 n-1 n−1对相差为 1 1 1的数。
因为没有 0 0 0,所以不存在比 1 1 1小 1 1 1的数,由此特殊条件我们可以判断出最小的数 1 1 1所在的位置。之后依据 n − 1 n-1 n−1对“大1关系”,就可以还原出原始数组的样子。
AC代码
/** @Author: LetMeFly* @Date: 2021-10-17 20:10:26* @LastEditors: LetMeFly* @LastEditTime: 2021-10-19 00:07:29*/ // LastEditTime: 2021-10-17 20:59:28
#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
struct Conditions {int l, r; // 下标为l的元素比下标为r的大1// bool xd;
} cond[1010];
int sx[1010] = {0}; // sx[i]用来记录下标为i的数是否当过“比其他数大1的数”。如果没有,那么下标为i的数就是1
int Next[1010]; // Next[i]代表下标为i的数+1的数的下标
int ans[1010]; // 答案。ans[i]代表下标为i的数的真实隐藏的数
int main() {int n;cin >> n; // n个数int cnt = 0; // 现在又了cnt个“大1关系”for (int i = 1; i <= n; i++) {printf("? "); // 询问for (int j = 1; j <= n; j++) {if (j != i) printf("2 "); // 这个数之外的数都加2else printf("1 "); // 这个数+1}puts(""); // 换行fflush(stdout); // 清空缓冲区int answer; // 这个询问的回答cd(answer); // scanf("%d", &answer);if (answer != 0 && answer < i) { // answer=0代表加上后没有相同的数,answer=i说明要找的数在i后面cond[cnt].l = answer; // 回答的数的下标cond[cnt].r = i; // 比只加了1的数 小1// cond[cnt].xd = true;cnt++; // 已有的“大1关系”的数++}printf("? "); // 询问for (int j = 1; j <= n; j++) {if (j != i) printf("1 "); // 其他数+2else printf("2 "); // 这个数+1}puts(""); // 换行fflush(stdout); // 清空缓冲区cd(answer); // 同上if (answer != 0 && answer < i) {cond[cnt].l = i;cond[cnt].r = answer;// cond[cnt].xd = false;cnt++;}}for (int i = 0; i < cnt; i++) {Next[cond[i].l] = cond[i].r; // 下标为cond[i].l的数 +1得到的数 的下标是cond[i].rsx[cond[i].r]++; // cond[i].r当过“比其他数大1的数”}int one; // 1所在的下标for (int i = 1; i <= n; i++) {if (!sx[i]) { // 这个数没当过“比其他数大1的数”one = i; // 1就是它了break;}}for (int i = 1; i <= n; i++) { // 一共要还原n个数ans[one] = i; // 答案(原始的隐藏的数)one = Next[one]; // 比它大1的数}printf("! "); // 输出最终答案for (int i = 1; i <= n; i++) {printf("%d ", ans[i]);}puts(""); // 换行return 0;
}
原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/120837226
这篇关于CodeforcesRound#749(Div.1.2basedonTechnocup2022EliminationRound1)-D.Omkar and the Meaning of Life-题解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!