EOJ Monthly 2018.9 B. 解密信件

8 篇文章 0 订阅
2 篇文章 0 订阅

题目链接:

EOJ Monthly 2018.9 B. 解密信件

题意概括:

对于某个长度为 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(闭区间)的子串倒置。

数据范围:

1\le T\leq 1000

1\leq x \leq n \leq 10^{18}

题解分析:

这里的做法就是二分答案区间,递归模拟。每次维护两对变量:

  • 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);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值