Codeforces Round 883 (Div. 3)
F. Rudolph and Mimic
题目链接
题意:
这是一项interactive task(交互题)。
鲁道夫是一位研究外星生物的科学家。鲁道夫面前有一个房间,房间里散落着 n n n 种不同的物体。在这些物体中,有一个神奇的生物——模仿者,它可以变成任何物体。他已经在这个房间里伪装好了,鲁道夫需要通过实验找到他。
实验分几个阶段进行。每个阶段都会发生以下情况:
- 鲁道夫查看房间里的所有物品,并写下它们的类型。每个物体的类型都用数字表示;同一类型的物体可能有好几个。
- 检查完毕后,鲁道夫可以指出一个他认为是模仿品的物体。之后,实验就结束了。鲁道夫只有一次尝试的机会,所以如果他不确定模仿者的位置,就会进行下一步。
- 鲁道夫可以从房间里拿走任意数量的物品(可能是零)。然后,鲁道夫离开房间,此时所有的物体,包括拟态物体,会相互混合,它们的顺序也会改变,拟态物体可以变成任何其他物体(即使是房间里没有的物体)。
- 之后,鲁道夫回到房间,重复这个阶段。模仿者可以不改变外观,但不能连续两个阶段以上保持同一个物体。
鲁道夫的任务是在不超过五个阶段内探测到模仿者。
输入:
第一行包含一个整数 t t t ( 1 ≤ t ≤ 1000 ) (1 \le t \le 1000) (1≤t≤1000) - 测试用例数。 ( 1 ≤ t ≤ 1000 ) (1 \le t \le 1000) (1≤t≤1000) - 测试用例的数量。
每个测试用例的第一行包含一个整数 n n n ( 2 ≤ n ≤ 200 ) (2 \le n \le 200) (2≤n≤200) - 房间中的物体数量。 ( 2 ≤ n ≤ 200 ) (2 \le n \le 200) (2≤n≤200) - 房间中对象的数量。
每个测试用例的第二行包含 n n n 个整数 a 1 a_1 a1 , a 2 a_2 a2 ,…, a n a_n an 。 ( 1 ≤ a i ≤ 9 ) (1 \le a_i \le 9) (1≤ai≤9) -对象类型。
交互:
阅读完输入数据集的说明后,您必须进行不超过 5 5 5次查询。阅读输入数据被视为第一阶段的开始,模仿器可能已经开始变化。
请求是一行。行的第一个字符表示请求类型。要删除对象,请打印"-"。然后打印数字 k k k --要删除多少个对象。然后是 k k k 个数字–对象在当前位置的索引。索引从 1 开始。您可以删除模仿对象,但在这种情况下,您将无法指向它,并将得到 "错误答案 "的判决。
作为对请求的回应,您将收到一行包含整数的信息–移除和混合后房间中剩余的物品。
要指明模仿对象的位置,请打印"!",然后打印模仿对象的索引。
如果正确指定了模仿器的位置,任务将被视为已完成。
思路:
其实刨去交互标签,这个题的思路还是蛮简单的,虽然物品的顺序会变,但是除了模仿者以外的物品一定不会改变类型,也就是每种类型的个数一定是不变的。如果模仿者要变成其他类型的物品,那么变成的类型一定会凭空多出一个来。那么其他类型的物品就都可以删掉了。
因为上面说了模仿者不会两个回合以上维持同一个类型,因此至多两个回合就会有一种类型的物品凭空多一个,那么我们就只留下这种类型的物品,随后再至多两回合,模仿者会变成其他类型的物品来送死,这时候凭空出现的那个就是模仿者。
具体来说,存储一下出房间之前每种类型个数,然后回来读取物品。如果有某种类型数量比离开前多1,而且这个类型就一个,那么它就是模仿者,否则把其他类型都删掉。如果找到了模仿者就退出循环,否则把这些类型当成下一轮离开房间时的类型个数,如此循环。
它说了,你可以删掉模仿对象,但是这会导致你永远不可能找到模仿对象了,所以最后一定会WA。所以一开始的时候没有把握就不碰,它给的这些样例纯纯脑瘫。
难的是交互部分,一个不小心就是ILE。我的建议是每行结尾用cout输出endl来换行。交互题是两个程序通过标准输出输出进行对话,而标准输入输出stdin
和stdout
都是行缓冲OI,所以每一行输出结束后都要清空缓冲区。
程序标准输入输出存在一个缓冲区(可以理解为输入时窗口中光标所在的那一行),你可以对缓冲区内的内容进行编辑,它暂时不会将缓冲区的内容给程序输入,因此要决定输入的时候我们会用换行把数据输入,这个操作就会引起 清空缓冲区,每次缓冲区清空时程序才进行读入。
然后呢,你的程序看似输出了内容,但是由于没有清空缓冲区,实际上并没有给题目程序输入(所以有的评测平台会给TLE判决),这个fflush(stdout) 或 C++ 中的 cout.flush() 完成的工作就是清空缓冲区,将缓冲区的内容给题目程序进行输入,endl在换行的同时也会清空缓冲区。输出’\n’也可以,不过不如endl和flush保险。
实际上我们在屏幕上看到的程序输出也是行缓冲,本来不应该在输出换行前进行输出的,但是被某些配置或者优化给提前刷新了。
code:
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
int T,n;
vector<int> a(10),t(10);
vector<vector<int> > item(10,vector<int>(200));
int main(){
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=9;i++)
a[i]=0;
for(int i=1,tmp;i<=n;i++){
cin>>tmp;
a[tmp]++;
}
a[0]=n;
cout<<"- 0"<<endl;
while(true){
for(int i=0;i<=9;i++)
t[i]=item[i][0]=0;
for(int i=1,tmp;i<=a[0];i++){
cin>>tmp;
item[tmp][++item[tmp][0]]=i;//item[tmp][0]存储这tmp类型的物品的个数
t[tmp]++;
}
int f=0;
for(int i=1;i<=9;i++){
if(a[i]<t[i])f=i;
}
if(f==0){
t[0]=a[0];
a=t;
cout<<"- 0"<<endl;
continue;
}
else if(t[f]==1){
cout<<"! "<<item[f][1]<<endl;
break;
}
t[0]=t[f];
cout<<"- "<<a[0]-t[0];
for(int i=1;i<=9;i++)
if(i!=f){
for(int j=1;j<=item[i][0];j++)
cout<<" "<<item[i][j];
t[i]=0;//删掉
}
a=t;
cout<<endl;
}
}
return 0;
}