[题解]CF1589D
题意:
sb交互题 。。。
有一个个数的排列,为级,初始,(测试者)选出一个三元组 ,并对分别倒序。
你可以询问区间的逆序对数,至多不超过40次,推测并回答出三元组。
分析以及思维过程:
首先看到数据范围为 级别,询问次数不超过40,故考虑 级别的算法。
为方便书写 表示询问的逆序对数。
第一反应:
考虑二分,首先 ,然后对于区间查找左端点,如果不等于那么左端点就在,因为逆序对减少了,反之则在
二分出左端点、右端点,即可求出中间点,区间长度为那么。
交上去才发现询问次数过多……
因为二分左端点和右端点的时间复杂度都是的,所以总查找次数会达到次
所以我们只能二分一次。
先二分左端点,并推出
利用好这个排列的特征 , 它本身单调递增,那么颠倒的部分就是单调递减的 。
如果有一个单调递减的序列
我们在此之前加一个数 那么逆序对数会增加组
利用这个性质,我们询问这之差就是造成的逆序对数,既
可以推出
推出后同理即可求出
ACcode:
C++
#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[102],b[102],n,t,l,r,zs,i,j,k;
bool check(int a,int b)
{
cout<<'?'<<' '<<a<<' '<<b<<endl;
cout.flush();
int p;
cin>>p;
if(p==zs) return 1;
return 0;
}
int asknxd(int l,int r)
{
cout<<'?'<<' '<<l<<' '<<r<<endl;
cout.flush();
int p;
cin>>p;
return p;
}
signed main()
{
cin>>t;
while(t--)
{
cin>>n;
cout<<'?'<<' '<<1<<' '<<n<<endl;
cout.flush();//因为这行痛失D题
cin>>zs;
l=1;r=n;
int ans = -1;
while(l<=r)
{
int mid = l+r>>1;
if(check(mid,n)) ans = mid ,l=mid + 1;
else r=mid-1;
}
i= ans ;
int nxd1 =asknxd(i,n);
int nxd2 =asknxd(i+1,n);
j=i+(nxd1-nxd2)+1;
nxd1 =asknxd(j,n) ;
nxd2 =asknxd(j+1,n) ;
k=j+(nxd1-nxd2);
cout<<'!'<<' '<<i<<' '<<j<<' '<<k<<endl;
cout.flush();
}
}
很不错的一道题,考完后才发现非常简单
本文已经结束了。本文作者:ღꦿ࿐(DeepSea),转载请注明原文链接:https://www.cnblogs.com/Dreamerkk/p/17970994,谢谢你的阅读或转载!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步