codeforces(1045)(div2) E. Power Boxes

E.电源箱

每次测试时限: 2 秒

每次测试的内存限制:256 兆字节

输入:标准输入

输出:标准输出

这是一个互动问题。

给你 nnn 个方格,索引从 111 到 nnn 。这些方格看起来完全相同,但是每个方格都有一个隐藏的幂值 aia_iai ,它要么是 111 要么是 222 。

您想确定每个方格的幂值。为此,您将进行以下实验。起初, iii -th 方框被放置在数线( 1≤i≤n1 \le i \le n1≤i≤n )上的坐标 iii 处。

您可以进行以下两种类型的查询:

  • 交换 xxx " ( 1≤x≤n−11 \le x \le n - 11≤x≤n−1 ):交换当前位于坐标 xxx 和 x+1x + 1x+1 的方格。请注意,此更改是永久性的,会影响所有后续查询。
  • 投掷 xxx " ( 1≤x≤n1 \le x \le n1≤x≤n ):向位于坐标 xxx 的方框投掷小球。如果方框的幂值为 ppp ,则小球向前移动 ppp 个单位,到达坐标 x+px + px+p 。如果在新坐标处有一个方格,小球会使用该方格的幂再次跳跃。这个过程一直持续到小球落在一个没有方框的坐标上。作为回答,您将得到小球在停止前的总跳跃次数。

您的任务是使用不超过 ⌈3n2⌉\left\lceil \frac{3n}{2} \right\rceil⌈23n⌉ 的查询(包括交换和抛掷查询)确定每个方格的幂值。
输入

每个测试包含多个测试用例。第一行包含测试用例的数量 ttt ( 1≤t≤5001 \le t \le 5001≤t≤500 )。测试用例说明如下。

每个测试用例的第一行也是唯一一行包含一个整数 nnn ( 2≤n≤10002 \le n \le 10002≤n≤1000 ) - 盒子的数量。

保证所有测试用例中 nnn 的总和不超过 100010001000 。
互动

每个测试用例的交互开始于读取整数 nnn 。

要进行查询,请按以下格式之一输出一行:

  • "交换 xxx "(不带引号)( 1≤x≤n−11 \le x \le n - 11≤x≤n−1 ):交换当前位于坐标 xxx 和 x+1x + 1x+1 的方框。

  • 扔 xxx "(不带引号)( 1≤x≤n1 \le x \le n1≤x≤n ):向位于坐标 xxx 的盒子投掷一个球。评委将给出一个整数,代表小球停止前的跳跃次数。

请注意,查询是**区分大小写的。

确定每个方框的功率值后,按以下格式输出一行:

  • "! a1 a2 ... ana_1 \space a_2 \space \ldots \space a_na1 a2 ... an "(不带引号):这里, aia_iai 是最初位于坐标 iii ( 1≤i≤n1 \le i \le n1≤i≤n )的方格的幂值。提交最终答案后,进入下一个测试用例。

请注意,提交上一个查询的最终答案不***计入 ⌈3n2⌉\left\lceil \frac{3n}{2} \right\rceil⌈23n⌉ 个查询的限制中。

如果您的程序在一个测试用例中的查询次数超过 ⌈3n2⌉\left\lceil \frac{3n}{2} \right\rceil⌈23n⌉ ,您的程序必须立即终止,并收到 "错误答案 "的判决。否则,程序可能会收到任何其他判决。

输出查询后,不要忘记输出行尾并刷新输出。否则,您将收到 "超过闲置限制 "的提示。为此,请使用

  • fflush(stdout) 或 C++ 中的 cout.flush();
  • Java 中使用 System.out.flush();
  • Python 中的 sys.stdout.flush();
  • Rust 中的 std::io::stdout().flush();
  • 请参见其他语言的文档。

交互器是非适应性;在整个交互过程中,方框的幂值保持不变。

黑客*

要黑客攻击,请使用以下格式。

第一行应包含一个整数 ttt ( 1≤t≤5001 \le t \le 5001≤t≤500 ) - 测试用例数。

每个测试用例的第一行包含一个整数 nnn ( 2≤n≤10002 \le n \le 10002≤n≤1000 ) - 盒子的数量。

每个测试用例的第二行包含 nnn 个整数 a1,a2,...,ana_1,a_2,\ldots,a_na1,a2,...,an ( 1≤ai≤21 \le a_i \le 21≤ai≤2 ) - 每个方框的幂值。

所有测试用例中 nnn 的总和不应超过 100010001000 。

以下是示例中的交互过程:

解决方案 评审 解释
有 222 个测试用例。
4 第一个测试用例中有 444 个方框。隐藏功率值为 a=[2,1,2,1]a = [2,1,2,1]a=[2,1,2,1] 。
扔 2 2 向位于坐标 222 的方框扔一个球。小球经过坐标 2→3→52 \to 3 \to 52→3→5 并停在坐标 555 ,因此响应为 222 。
交换 3 交换位于坐标 333 和 444 的盒子。现在方框 333 位于坐标 444 处,方框 444 位于坐标 333 处。
向位于坐标 222 的方格投掷一个小球。球经过坐标 2→3→4→62 \to 3 \to 4 \to 62→3→4→6 ,停在坐标 666 处,因此响应为 333 。请注意,由于交换了坐标,响应是不同的。
向坐标 111 处的方框投掷小球。小球经过坐标 1→3→4→61 \to 3 \to 4 \to 61→3→4→6 并停在坐标 666 处,因此响应为 333 。
!2 1 2 1
第二个测试案例中有 222 个方框。隐藏的功率值为 a=[1,2]a = [1, 2]a=[1,2] 。
向坐标 111 处的方格投掷小球。小球经过坐标 1→2→41 \to 2 \to 41→2→4 ,停在坐标 444 ,因此响应为 222 。
交换 1 交换位于坐标 111 和 222 的盒子。现在方框 111 位于坐标 222 ,方框 222 位于坐标 111 。
抛 1 1 向位于坐标 111 的方格抛掷小球。球经过坐标 1→31 \to 31→3 并停在坐标 333 处,因此响应为 111 。
!1 2

示例输入和输出中的空行只是为了提高可读性;您不必在解法中输出这些空行。

请注意,在第一个测试用例中,给出的查询实际上不足以唯一确定幂值;给出查询只是为了说明输入/输出格式。

本人思路

  • 首先大家题都看了吧,就是让你在⌈3n2⌉\left \lceil\frac{3n}{2} \right \rceil⌈23n⌉次数下找每个点的值;
  • 我们先想一下,想要求点的值,我们先用d[i]d[i]d[i]来保存每个点往后的跳的次数
  • 接下来我们就可以考虑两种情况,假设现在点为i,那么就看d[i+1]d[i+1]d[i+1]与d[i+2]d[i+2]d[i+2],d[i+1]!=d[i+2]d[i+1]!=d[i+2]d[i+1]!=d[i+2]就很简单,就可以直接判断求值了,而dp[i+1]==dp[i+2]dp[i+1]==dp[i+2]dp[i+1]==dp[i+2]就需要了,先不管标记一下;
  • 接下来就判断标记点,把 i与i+1交换,因为i+1肯定是确认的,那么我们就可以确定i的值了,唯一就是加了个交互式;

(蒻蒻)代码欣赏

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2005;
int d[N],a[N],n,aa;
bool vis[N];
void solve()
{
    for(int i=1;i<n;i++)
    {
        if(vis[i])
        {
            cout<<"swap "<<i<<'\n';
            cout.flush();
            cout<<"throw "<<i+1<<'\n';
            cout.flush();
            cin>>aa;
            if(aa==d[i+2]+1)
                a[i]=1;
            else
                a[i]=2;
        }
    }
    if(vis[n])
    {
        cout<<"swap "<<n-1<<'\n';
        cout.flush();
        cout<<"throw "<<n-1<<'\n';
        cout.flush();
        cin>>aa;
        if(aa==2)
            a[n]=1;
        else
            a[n]=2;
    }
    cout<<"! ";
    for(int i=1;i<=n;i++)
    {
        cout<<a[i]<<" ";
    }
    cout<<'\n';
    cout.flush();
}
signed main()
{
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int _,m;
    cin>>_;
    while(_--)
    {
        cin>>n;
        fill(vis+1,vis+1+n,0);
        d[n+1]=0;d[n+2]=0;
        for(int i=n;i>=1;i--)
        {
            if(d[i+1]==d[i+2])
            {
                vis[i]=1;
                d[i]=d[i+1]+1;
            }
            else
            {
                cout<<"throw "<<i<<'\n';
                cout.flush();
                cin>>m;
                d[i]=m;
                if(d[i]==d[i+1]+1)
                    a[i]=1;
                else
                    a[i]=2;
            }
        }
        solve();
    }
    return 0;
}```