1. 程式人生 > 其它 >LG 題解 P7345 【DSOI 2021】吟唱的金色花海

LG 題解 P7345 【DSOI 2021】吟唱的金色花海

目錄

題目傳送

吐槽幾句

私以為鄙人之題解略易之與其他兩篇題解。

他們都寫的太長了,那麼多圖根本看不下去,還是我的比較清晰,程式碼也十分好寫。

Solution

主要思想就是二分。

首先題目給你了位置 \((x_0, y_0)\) 和一個時間 \(t\)

因為從某個起點 \((sx, sy)\) 擴充套件 \(t\) 次後,\((x_0,y_0)\) 一定在它的邊界上。

所以我們可以搞出這麼一張圖。

可能有的人看到這個圖就瞬間明白了。下面再詳細說一下。

根據這個圖不難發現,我們只要找到 \((x_0,y_0)\) 的一個(關於 BD)的對稱點 \(F\),然後它到中點的距離 \(l\)

可以求出,又因為我們知道了 \((x_0,y_0)\)\((sx,sy)\) 的曼哈頓距離為 \(t\),那我們就可以直接表示出 \((sx,sy)\)

那麼這個點 \(F\) 怎麼求?想想那個 \(MAX\) 值為什麼帶了一個 \(\log\),就是讓我們用二分啊。

因此這個 \(F\) 的特徵就是最遠的被染成金色的鬱金香,我們可以二分 \((x_0,y_0)\) 這個點向右走幾步才能到達這個 \(F\)

但是最遠的時候是 \(AD = 2t\),好像比需要的次數多 \(1\)。我們繼續觀察發現 \((x_0,y_0)\)\(F\) 的距離一定為偶數,所以二分的範圍設為 \([1,t]\)

即可。

需要注意我們還要確定的一個資訊是延伸的方向,這個可以通過分別詢問它的右邊和下邊是否是金色鬱金香得到。

所以總的詢問次數為 \(\log t + 2 \le MAX\),可以通過。

實現細節看程式碼吧。

Code

/*
Work by: Suzt_ilymics
Problem: 不知名屑題
Knowledge: 垃圾演算法
Time: O(能過)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL long long
#define orz cout<<"lkp AK IOI!"<<endl

using namespace std;
const int MAXN = 1e5+5;
const int INF = 1e9+7;
const int mod = 1e9+7;

int T, t, sx, sy, k;

int read(){
    int s = 0, f = 0;
    char ch = getchar();
    while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
    while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
    return f ? -s : s;
}

int main()
{
	T = read();
	while(T--) {
	    t = read(), sx = read(), sy = read(), k = read();
	    if(t == 0) {
	        printf("1 %d %d\n", sx, sy);
	        fflush(stdout);
	        continue;
        }
	    int fx1, fx2, x; // 1 表示上左,2 表示下右 
        printf("0 %d %d\n", sx + 1, sy);
        fflush(stdout);
        x = read();
        if(x) fx1 = 1; else fx1 = -1;
        printf("0 %d %d\n", sx, sy + 1);
        fflush(stdout);
        x = read();
        if(x) fx2 = 1; else fx2 = -1; // 用 1/-1 方便後面的計算 
        int l = 1, r = t, ans = 0;
        while(l <= r) {
            int mid = (l + r) >> 1;
            printf("0 %d %d\n", sx, sy + 2 * fx2 * mid);
            fflush(stdout);
            x = read();
            if(x) ans = mid, l = mid + 1;
            else r = mid - 1;
        }
        int ex = sx, ey = sy + 2 * fx2 * ans; // 求得的 F 點 
        int Mid = (sy + ey) / 2;
        int ty = Mid, tx = sx + fx1 * (t - abs(Mid - ey)); // 直接求出終點 
        printf("1 %d %d\n", tx, ty);
        fflush(stdout);
    }
    return 0;
}