加载中...

交互题专题

前言

交互题是一类特殊的算法题, 每次输入数据, 系统都会给出数据进行反馈, 需要通过系统反馈的数据, 得到某个答案. 交互题在蓝桥杯和OI比赛中都不会考察, CF偶尔会有交互题. 交互题的输入输出比较特别, 需要了解交互题独有的输入输出格式. 最近参加的团队程序设计天梯赛, 模拟赛中考察了交互题, 觉得交互题还是有必要记录一下的.




交互题介绍

通俗来讲, 交互题与平时题目的输入输出反过来, 是让你设计程序去向用户提出询问, 由用户给出答案, 并且在这基础上由程序推断出正确答案的一种形式.

C++的交互题, 每次输出后都得加 fflush(stdout)


交互题的特殊错误:

  • 选手每一次输出后都需要刷新缓冲区, 否则会引起 Idleness limit exceeded 错误. 另外, 如果题目含多组数据并且数据可以在未读入所有数据前就知道答案, 也仍然要读入所有数据, 否则同样会因为读入混乱引起 ILE (可以一次提出多次询问, 一次接收所有询问的回答). 同时尽量不要使用快读.
  • 如果程序查询次数过多, 则在 Codeforces 上会给出 Wrong Answer 的评测结果(不过评测系统会说明 Wrong Answer 的原因), 而 UVA 会给出 Protocol Limit Exceeded (PLE) 的评测结果.



例题

Codeforces Round 356 (Div. 1) A. Bear and Prime 100

题目大意: 系统生成了一个数, 你需要在20次询问内给出这个数是质数还是合数. 每次询问一个数, 它会回答这个数是不是它的因数.

思路: 询问[2, 50] 内的质数, 如果该质数x是它的因数, 则继续询问\(x^{2}\)是不是它的因数(判断是否这个数就是这个质数x), 若该数在[2, 100] 范围内有两个及以上的因数, 则为合数. 若只有一个因数(它本身), 则为质数.

注意: C++的交互题, 每次输出后都得加 fflush(stdout)


#include<iostream>
#include<algorithm>

using namespace std;

bool is_prime(int x)
{
    for(int i=2;i<=x/i;i++)
        if(x%i==0)return false;
    return true;
}

bool divisible(int x)
{
    cout<<x<<'\n';
    fflush(stdout);
    string str;
    cin>>str;
    if(str=="yes")return true;
    else return false;
}

int main()
{
    int maxx=100;
    int cnt=0;
    
    for(int i=2;i<=maxx/2;i++)
        if(is_prime(i))
        {
            if(divisible(i))
            {
                cnt++;
                if(i*i<=maxx)
                    if(divisible(i*i))cnt++;
            }
        }
    
    if(cnt>=2)cout<<"composite"<<'\n';
    else cout<<"prime"<<'\n';
    fflush(stdout);
    
    return 0;
}



Codeforces Round 859 (Div. 4) E. Interview

题目大意: 给定n堆石头, 并告诉你第i堆石头的重量是ai, 但实际上有一堆石头的重量比告知的大1, 需要在30次询问内, 找出这是第几堆石头. 每次询问, 先输入询问的石头堆数, 再输入石头堆的下标, 系统会回答这些石头实际的总重量.

思路: 二分、前缀和


#include<iostream>
#include<algorithm>

using namespace std;

const int N=200010;
int a[N],s[N];

bool ask(int l,int r)
{
    cout<<"?"<<' ';
    cout<<r-l+1<<' ';
    for(int i=l;i<=r;i++)cout<<i<<' ';
    fflush(stdout);
    
    long long sum=s[r]-s[l-1];
    long long ans;
    cin>>ans;
    return sum==ans;
}

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            s[i]=s[i-1]+a[i];
        }
        
        int l=1,r=n;
        while(l<r)
        {
            int mid=(l+r)/2;
            if(ask(l,mid))l=mid+1;
            else r=mid;
        }
        cout<<"!"<<' '<<l<<'\n';
        fflush(stdout);
    }
    return 0;
}



Technocup 2017 - Elimination Round 1 (Unofficially Open for Everyone, Rated for Div. 2)

题目大意: 系统生成了一个长度为n (\(n\ge\) 3) 的数列, 你需要经过不超过n次询问, 猜出这个数列. 每次询问, 你可以输入两个下标 i 和 j (i \(\neq\) j , 且 i , j 都属于1到n) , 系统会回复ai + aj 的和.

思路: 先询问 a1 + a2 , a2 + a3 , a3 + a1 , 得到 a1 , a2 , a3 的值, 之后(n - 3)次, 每次询问a1 和 ai , 得到 ai 的值.


#include<iostream>
#include<algorithm>

using namespace std;

const int N=5010;
int a[N];
int n;

int main()
{
    cin>>n;
    
    int one,two,three,sum;
    cout<<"? 1 2"<<'\n';
    fflush(stdout);
    cin>>three;
    cout<<"? 1 3"<<'\n';
    fflush(stdout);
    cin>>two;
    cout<<"? 2 3"<<'\n';
    fflush(stdout);
    cin>>one;
    sum=(one+two+three)/2;
    a[1]=sum-one;
    a[2]=sum-two;
    a[3]=sum-three;
    
    for(int i=4;i<=n;i++)
    {
        cout<<"? 1 i"<<'\n';
        fflush(stdout);
        int x;
        cin>>x;
        a[i]=x-a[1];
    }
    
    cout<<"!"<<' ';
    for(int i=1;i<=n;i++)cout<<a[i]<<' ';
    fflush(stdout);
    
    return 0;
}


posted @ 2023-04-27 20:35  邪童  阅读(298)  评论(0编辑  收藏  举报