[Codeforces 1589D] Guess the Permutation | 交互 思维 二分
题目链接
题意
多组输入:{
每组给出一个n,有一个长度为n的数列,在开始的时候
a
i
=
i
a_i=i
ai=i,有三个数
i
,
j
,
k
i,j,k
i,j,k
数列反转了
[
i
,
j
−
1
]
[
j
,
k
]
[i,j-1][j,k]
[i,j−1][j,k]
要求出这三个数,可以对系统进行询问
[
l
,
r
]
[l,r]
[l,r]区间内逆序对的个数,会返回这个值
}
思路:
对于这个反转之后的数列来说,
[
1
,
i
]
[1,i]
[1,i]之内的逆序对的个数为0
所以在左端点固定(= 1)的情况下,二分右端点找到这个
i
i
i
然后对于一段反转之后的数列:
5
4
3
2
1
5 \ \ \ 4 \ \ \ 3\ \ \ 2\ \ \ 1
5 4 3 2 1
逆序对数量:
0
1
2
3
4
0 \ \ \ 1 \ \ \ 2\ \ \ 3\ \ \ 4
0 1 2 3 4
假如去掉前面的5
那么就为
0
1
2
3
\ \ \ \ \ 0\ \ \ 1\ \ \ 2\ \ \ 3
0 1 2 3
两个做差发现值为4,+1就可以得到逆转的长度为5
所以说:
j = ask(i,n) - ask(i+1,n) + 1 + i;
k = j + ask(j,n) - ask(j+1,n);
而在二分左端点 l l l的过程也不会很大,问题解决
ac_code:
ll ask(ll l,ll r){
ll sysin = 0;
cout <<"? " << l << ' ' << r << endl;
cout.flush();
cin >> sysin;
return sysin;
}
int main() {
int _ = read;
while(_ --){
ll n = read;
ll l = 1,r = n;
ll i,j,k;
i = j = k = 0;
while(l < r) {
ll mid = l+r >> 1;
if(ask(1,mid)) r = mid;
else l = mid + 1;
}
i = l - 1;
j = ask(i,n) - ask(i+1,n) + 1 + i;
k = j + ask(j,n) - ask(j+1,n);
cout << "! " << i << ' ' << j << ' ' << k << endl;
cout.flush();
// printf("! %lld %lld %lld\n",i,j,k);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】