题目链接:
题意概括:
对于某个长度为 n,下标从 1 开始的字符串要进行加密,只要调用 encrypt(1, n)
即可
有 T 次独立询问,每次询问位置 x,表示加密后的位置,求这个位置在加密前是在什么位置
题目给的加密方式:
char letter[];
void encrypt(l, r) {
if (l < r) {
reverse letter[l..r];
k = (r - l + 1) / 2;
encrypt(l, l + k - 1);
encrypt(l + k, r);
}
}
其中 reverse letter[l..r] 是将 letter 从 l 到 r(闭区间)的子串倒置。
数据范围:
题解分析:
这里的做法就是二分答案区间,递归模拟。每次维护两对变量:
- L , R : 表示当前区间的数在加密前的区间
- l , r : 表示当前区间
从初始的串模拟递归 (就是加密的过程) ,每次按 x 的值在 l, r 之间二分,只用进入一侧递归便可,做好 L,R 的划分和反转
搜到 l == r && l == x 时,L 或 R 便是答案
AC代码:
#include <stdio.h>
using namespace std;
typedef long long ll;
ll n, x, ans;
void search(ll L, ll R, ll l, ll r) {
if (l < r) {
ll k = (r - l + 1) / 2;
if (x <= l + k - 1)
if (R >= L) search(R, R - k + 1, l, l + k - 1); //左
else search(R, R + k - 1, l, l + k - 1);
else
if (L >= R) search(L - ((r - l) - k), L, l + k, r); //右
else search(L + ((r - l) - k), L, l + k, r);
}
else if (l == r && l == x)
ans = L;
}
int main()
{
int T;
scanf("%d", &T);
while (T --) {
scanf("%lld%lld", &n, &x);
search(1, n, 1, n);
printf("%lld\n", ans);
}
}