EOJ Monthly 2018.9 B. 解密信件
阿新 • • 發佈:2018-12-10
題目連結:
題意概括:
對於某個長度為 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); } }