首页 > 其他分享 >I. 西行妖下题解

I. 西行妖下题解

时间:2023-01-06 16:01:30浏览次数:67  
标签:tmp 数字 int 题解 询问 妖下 西行 del ans

题目内容

原题链接


样例输入

5

2

0

1

样例输出

? 4 4 2 3 2

? 3 5 1 5 5

? 5 2 4 3 1

! 3 2 1 5 4

题解

首先,题目有一个很难解决的痛点,就是他只会返回最前面的那个下标。那我们就不妨倒着做,从后往前处理。
先考虑最后一个数字。我们如果发出类似 "1 1 1 1 2" 这样的询问,就相当于把最后一个数字抬高了 \(1\), 相应地,改成 "1 1 1 1 3" 就是把最后一个数字抬高了 \(2\)。
我们先不断抬高最后一个数字,期间也记录下来他和前面某些数字的关系(前面这个数字比最后一位大 \(k\)),这样我们在知道最后一个数字之后就能直接推出有关系的数字,减少询问次数。

可以发现,最后一个数字被抬高某个 \(k\) 之后,交互器一定会返回 \(0\),因为此时他比最大值 \(n\) 大了 \(1\)。那么这个时候,我们就找出来了最大值 \(n\) 的位置以及最后一个数字的值。(二者当然有可能重合)。
在这里,假设我们花了 \(M\) 次询问,那么这 \(M\) 次询问也一定会让我们知道 \(M\) 个值,所以没有超出一个数字平均两次询问机会的限制。

接着将指针前移。如果某个数字已经被确定,就略过他。直到某个未确认数字为止。类似地,我们不断抬高这个数字。先是获得了对他前面某些数字的关系,一直到交互器返回他自己的下标。注意,此时他身后的值都已经确定。那么这里就一定是他和他身后的最小值重合。(注意,他的身后不可能出现已经被确定的比当期数字小的值。因为若比他小的数字被确定,则当前数字也一定会在后面数字被不断抬高时确定。)所以直接记录最小值然后减掉抬高的部分便推出当前数字,同时也推出与他有关系的部分。

等到最后一个空余位置时,可以直接排除出他的值,进一步减少询问次数。

下面考虑上述操作询问次数的合法性。可以发现,对于“ 被关系推出来”的数字,他们消耗的次数都是 \(1\)。而对于需要我们主动确定(被抬升的数),他们也都是在询问至边界时被直接确定。所以上述流程的询问次数是 \(N\) 次,远小于题目给的限制 \(2 * N\)。

代码:

#include <bits/stdc++.h>
using namespace std;
#define N 100010

int n; 
int ans[N]; 

vector <pair<int, pair<int, int> > > G; 

int main(){
    memset(ans, 0, sizeof(ans)); 
    cin >> n; 
    int del = 1; 
    int tmp = 0; 
    int last = n; 
    while(666){
        printf("? "); 
        for(int i = 1; i < n; i++){
            printf("1 "); 
        }
        printf("%d\n", 1 + del);
		fflush(stdout);
        last = tmp;  
        scanf("%d", &tmp); 
         
        if(tmp != 0){
            G.push_back(make_pair(del, make_pair(n, tmp))); 
        } 
           
        else break; 
        del++; 
    }
    ans[last] = n; 
    ans[n] = n - del + 1; 
    for(auto it  : G){
        pair<int, int> t = it.second; 
        ans[t.second] = ans[t.first] + it.first; 
    }
    G.clear(); 

    int minn = 1e9; 

    for(int i = n; i >= 2; i--){
        if(ans[i]){
            minn = min(minn, ans[i]);
            continue; 
        }
        del = 1; 
        while(666){
            printf("? "); 
            for(int j = 1; j <= n; j++){
                if(j == i) printf("%d ", 1 + del); 
                else printf("1 "); 
            }
            printf("\n"); 
			fflush(stdout);
            scanf("%d", &tmp); 
             

            if(tmp == 0) break; 
            else if(tmp != i) G.push_back(make_pair(del, make_pair(i, tmp))); 
            else if(tmp == i){
                break; 
            }
            del++;  
        }
        if(tmp == 0) ans[i] = n - del + 1; 
        else if(tmp == i) ans[i] = minn - del; 
        minn = min(minn, ans[i]); 
        for(auto it : G){
            pair<int, int> t = it.second; 
            ans[t.second] = ans[t.first] + it.first; 
        }
        G.clear(); 
    }
    bool vis[1001]; 
    memset(vis, 0, sizeof(vis)); 
    for(int i = 2; i <= n; i++)
    	vis[ans[i]] = 1;
    for(int i = 1; i <= n; i++)
    	if(!vis[i]){
    		ans[1] = i;
    		break; 
		}
    printf("! ");
    for(int i = 1; i <= n; i++)
        printf("%d ", ans[i]);
    printf("\n"); 
    fflush(stdout);
    return 0; 
}

标签:tmp,数字,int,题解,询问,妖下,西行,del,ans
From: https://www.cnblogs.com/wondering-world/p/17030653.html

相关文章

  • Codeforces Round #842 (Div. 2) A-D题解
    比赛链接A、GreatestConvex非常的简单。根据样例直接猜是输出\(n-1\).上一个\(Python\)代码。T=int(input())whileT>0:T-=1n=int(input())......
  • USACO Au题解
    T1一眼背包,但是很怪考虑设dp[i][j][k]表示前i个物品还剩j个月饼还剩k个冰激凌。$O(n^4)$显然。转移O(n)枚举用钱还是优惠券。瓶颈在于冰激凌的优惠。考虑如何把这一......
  • idea 内存参数修改不生效问题解决 VM参数设置不生效解决
    提示:在idea的工具栏Help->EditCustomVMOptions内修改 对应参数-Xmx1024m后重启无效的再看下面的方法 问题:ieda的默认内存大小是1024M当我开多个工......
  • PIP 更新后不能使用的使用 提示: No module named 'pip'问题解决
    1、问题引入   正确安装Python以后,Python和PIP都可以正常使用。在使用pip安装其他库的时候,提示PIP版本过低,建议更新,结果更新时发生错误,导致PIP不能被识别,具体如下图......
  • 【题解】P2305 [NOI2014] 购票
    题意给定一棵边带权且以\(1\)为根的树,从后代结点\(u\)跳到祖先结点\(v\)的代价为\(dp_u+q_u\),其中\(p_u,q_u\)是给定的常数,\(d\)是\(u,v\)的树上距离。要......
  • BalticOI 2004 Sequence 题解
    题目链接在这里~对于序列\(\{a\}\),把每一个\(a_i\)减去一个\(i\),得到\(\{a'\}\)序列\(\{b\}\)同理。因为\(b_1<b_2<...<b_n\),故\(b_1'\leqslantb_2'\leqslant...\leqs......
  • ATC简单题解(不定时更新
    ABC129前三题略D.lamp虽然数据范围不大,但也没法暴力check,可以考虑分别维护每行(每列)障碍物的纵(横)坐标,可以考虑到插入std::vector中,然后对于每一个点查找横竖方向上的......
  • CF893D Credit Card 题解
    简要题意:你有一张信用卡,\(n\)天有\(n\)个操作,每次操作给定一个\(x\),如果\(x\)是\(0\)那么银行会查询信用卡里的金额,要保证金额是非负数;否则你卡里的金额会变化\(x......
  • 安徽农业大学寒假训练赛1题解
    D#include<bits/stdc++.h>usingnamespacestd;charg[10][10];intmain(){for(inti=1;i<=5;i++)scanf("%s",g[i]+1);//这样可以保证下标都从1......
  • 题解 : Luogu P2197 【模板】nim 游戏
    题目链接:link结论如果$a_1\oplusa_2\oplus...\oplusa_n\not=0$,则先手必胜证明操作到最后时,每堆石子数都是\(0\),\(0\oplus0\oplus...\oplus0=0......