STDIO交互题
引入
交互题这类型不同于普通的题。
可以理解为有个问题需要你解决,你通过输入某些东西。
表示你要问系统的问题,这时系统会回答你的问题。
在代码中的回答方式就是会输入某个东西就是系统给你的答案,通过这些信息你可以得到问题的解。
你是不可以自己测试的,只能提交给系统测试。
有个东西需要用到C++中的 fflush(stdout); ,这个东西是用来清空输出缓存区的。
因为你一直提问,一直输出,就需要清空输出缓存区。不然就有一些异常。
举一个最简单的例子:
猜数字我内心突然想到一个1到100之间的整数x。
现在我让你来猜,最多给你7次机会,每次你可以猜一个数字。
我会告诉你是大了,还是小了,还是猜对了。
方法就是二分。
下面给出几题简单的STDIO交互题。
例1 Bear and Prime 100
https://codeforces.com/problemset/problem/679/A
vjudge上也可以做:https://vjudge.net/problem/CodeForces-679A
题目大意:
有一个你未知的在2到100之间的整数,现在判断出他是质数还是合数。你最多可以提20个问题。
每个问题: x 。意思就是你问系统那个未知数能否被x整除,如果能整除,系统会输出yes,否则no。
最后的答案: prime 或 composite
思路:
把50以内的质数(外加4,9,25,49)都去提问一遍,如果有大于等于2次被整除,那么就是合数。否则就是质数。
代码:
#pragma GCC optimize(3,"Ofast","inline")
#pragma G++ optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define R register int
#define re(i,a,b) for(R i=a; i<=b; i++)
#define ms(i,a) memset(a,i,sizeof(a))
using namespace std;
typedef long long ll;
int a[19]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,4,9,25,49};
int sum;
int main() {
for(int i=0; i<19; i++) {
printf("%d\n",a[i]);
fflush(stdout);
string s;
cin >> s;
if(s=="yes") sum++;
if(sum==2) {
printf("composite\n");
return 0;
}
}
printf("prime\n");
return 0;
}
例2 Lost Numbers
原题:https://codeforces.com/contest/1167/problem/B
vjudge: https://vjudge.net/problem/CodeForces-1167B
题目大意:
有6个整数,分别是4,8,15,16,23,42,但是你不知道他们的顺序。现在你的任务就是要求出它们的顺序。
提问题的方法: 输出 ? i j ,意思就是你在问系统a[i]*a[j]的乘积是多少?
你最多可以提4次问题,然后就你要确定他们的顺序。
最后,如果你得到答案了,那么你就输出 ! a[1] a[2] a[3] a[4] a[5] a[6]
思路:
任意两个数的乘积都是不同的(本题的关键)
可以提问:
a[1]*a[2]
a[2]*a[3]
a[3]*a[4]
a[4]*a[5]
也可提问:
a[1]*a[2]
a[2]*a[3]
a[4]*a[5]
a[5]*a[6]
代码:
#pragma GCC optimize(3,"Ofast","inline")
#pragma G++ optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define R register int
#define re(i,a,b) for(R i=a; i<=b; i++)
#define ms(i,a) memset(a,i,sizeof(a))
using namespace std;
typedef long long ll;
int a[7]={0,4,8,15,16,23,42};
int b[5];
int main() {
for(int i=1; i<=4; i++) {
printf("? %d %d\n",i,i+1);
fflush(stdout);
scanf("%d",&b[i]);
}
while(1) {
if(a[1]*a[2]==b[1] && a[2]*a[3]==b[2] && a[3]*a[4]==b[3] && a[4]*a[5]==b[4]) {
printf("!");
for(int i=1; i<=6; i++) printf(" %d",a[i]);
break;
}
next_permutation(a+1,a+7);
}
return 0;
}
例3 Strange Device
原题:https://codeforces.com/problemset/problem/1270/D
vjudge:https://vjudge.net/problem/CodeForces-1270D
题目大意:
n,k是已知的,m是未知的。有n个互不相同的数(不知道的)。
你最多有n次提问的机会。
每次提问:你可以具体指出某k个位置,系统会告诉你这k个位置上第m小的数是多少。
求m。
思路:
询问k+1次,针对a[1]…a[k+1] 。
第一次询问 2…k+1
第二次询问 1,3,4…k+1
第三次循环 1,2,4,5…k+1
…
我们发现每次的答案一定是a[1]到a[k+1]里面的第m小或者第m+1小的数。
因为如果少的是比第m小的数大的数,那么答案就是第m小的数。
如果少的是比第m小的数小于等于的数,那么答案就是第m+1小的数。
探究第m小的数出现了几次? k+1-m个。
第m+1小的数出现了几次? m个。
所以答案就是k+1次询问里面大的那个数出现的次数 。
代码:
#pragma GCC optimize(3,"Ofast","inline")
#pragma G++ optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define R register int
#define re(i,a,b) for(R i=a; i<=b; i++)
#define ms(i,a) memset(a,i,sizeof(a))
using namespace std;
typedef long long ll;
int const N=505;
int n,k;
int a[N],vis[N];
int main() {
scanf("%d%d",&n,&k);
for(int i=1; i<=n; i++) {
if(i>k+1) break;
printf("? ");
for(int j=1; j<=k+1; j++) if(j!=i) printf("%d ",j);
fflush(stdout);
int p,num;
scanf("%d%d",&p,&num);
a[p]=num;
vis[p]++;
}
int mx=0,p=0;
for(int i=1; i<=n; i++) {
if(mx<a[i]) mx=a[i],p=i;
}
printf("! %d",vis[p]);
return 0;
}
其他练习
-
CodeForces-1063C Dwarves, Hats and Extrasensory Abilities
https://codeforces.com/problemset/problem/1063/C
https://vjudge.net/problem/CodeForces-1063C -
CodeForces-727C Guess the Array
https://codeforces.com/problemset/problem/727/C
https://vjudge.net/problem/CodeForces-727C -
CodeForces-713B Searching Rectangles
https://codeforces.com/problemset/problem/713/B
https://vjudge.net/problem/CodeForces-713B