P1228 地毯填补问题 解题报告

前言

这是一道思维+分治好题,值得纪念一下。

题目大意

一个 \(2^k \times 2^k\) 的地,第 \(x\)\(y\) 不能铺,其余的用这三种铺满,不能叠加铺,问方案:

比如 \(8 \times 8\) 的,公主站在 \((x, y)\) 处,则方案为:

考虑分治,我们先简单的分一下。

分治肯定需要状态都统一,很容易发现,这题不统一的点就在于四个块里面只有一个块有公主。

那么不如让每个块都有一个公主,其实样例这个图已经提示我们了,直接让这个东西变成不能站的就行了。

稍微列举一下,发现不管 \(k\) 是多少,这种让一个地毯变为“假公主”来维持状态统一的方法都适用。

那么接下来只需要判断真公主在上下左右哪一个块里,并且不断分割就行了。

代码实现

/*
    Author: Rainypaster(lhy)
    Time: 03/03/2024
    File: [Rainypaster] P1228.cpp
    Email: 2795974905@qq.com
*/
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

namespace IO
{
    template<typename T>
    T read(T x)
    {
        T sum = 0, opt = 1;
        char ch = getchar();
        while(!isdigit(ch)) opt = (ch == '-') ? -1 : 1, ch = getchar();
        while( isdigit(ch)) sum = (sum << 1) + (sum << 3) + (ch ^ 48), ch = getchar();
        return sum * opt;
    }

}
#define read IO::read(0)
#define rep(i, n) for(int i = 1; i <= n; i ++)
#define repa(i, n) for(int i = 0; i < n; i ++)
#define repb(i, n) for(int i = 1; i <= n; i ++)
#define repc(i, n) for(int i = 0; i < n; i ++)
#define lson (u << 1)
#define rson (u << 1 | 1)
#define gcd(a, b) __gcd(a, b)

const int N = 1e5 + 5;
int n, x, y;

void sol(int t, int sx, int sy, int x, int y)
{
    if(t == 0) return ;
    int mid = (pow(2, t)) / 2;
    if(x < sx + mid && y < sy + mid)
	{
		cout << sx + mid << ' ' << sy + mid << ' ' << 1 << endl;
		sol(t - 1, sx, sy, x, y), sol(t - 1, sx, sy + mid, sx + mid - 1, sy + mid);
		sol(t - 1, sx + mid, sy, sx + mid, sy + mid - 1), sol(t - 1, sx + mid, sy + mid, sx + mid, sy + mid);
	}
	else if(x < sx + mid)
	{
		cout << sx + mid << ' ' << sy + mid - 1 << ' ' <<  2 << endl;
		sol(t - 1, sx, sy, sx + mid - 1, sy + mid - 1), sol(t - 1, sx, sy + mid, x, y);
		sol(t - 1, sx + mid, sy, sx + mid, sy + mid - 1), sol(t - 1, sx + mid, sy + mid, sx + mid, sy + mid);
	}
	else if(y < sy + mid)
	{
		cout << sx + mid - 1 << ' ' << sy + mid << ' ' << 3 << endl;
		sol(t - 1, sx, sy, sx + mid - 1, sy + mid - 1), sol(t - 1, sx, sy + mid, sx + mid - 1, sy + mid);
		sol(t - 1, sx + mid, sy, x, y), sol(t - 1, sx + mid, sy + mid, sx + mid, sy + mid);
	}
	else
	{
		cout << sx + mid - 1 << ' ' << sy + mid - 1 << ' ' << 4 << endl;
		sol(t - 1, sx, sy, sx + mid - 1, sy + mid - 1), sol(t - 1, sx, sy + mid, sx + mid - 1, sy + mid);
		sol(t - 1, sx + mid, sy, sx + mid, sy + mid - 1), sol(t - 1, sx + mid, sy + mid, x, y);
	}
}

void solve()
{
    n = read;
    x = read, y = read;
    sol(n, 1, 1, x, y);
}

int main()
{
    int T = 1;
    while(T -- ) solve();
    return 0;
}

因为这是 Special Juge,所以方案可以随即顺序。

题外话

教练让我造一条可以使方案统一的题,于是就有了 ,要求输出整个地。

我们只要加一个地毯型号的判断以及填表。

题外话-代码

/*
    Author: Rainypaster(lhy)
    Time: 03/03/2024
    File: [Rainypaster] P1228.cpp
    Email: 2795974905@qq.com
*/
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

namespace IO
{
    template<typename T>
    T read(T x)
    {
        T sum = 0, opt = 1;
        char ch = getchar();
        while(!isdigit(ch)) opt = (ch == '-') ? -1 : 1, ch = getchar();
        while( isdigit(ch)) sum = (sum << 1) + (sum << 3) + (ch ^ 48), ch = getchar();
        return sum * opt;
    }

}
#define read IO::read(0)
#define rep(i, n) for(int i = 1; i <= n; i ++)
#define repa(i, n) for(int i = 0; i < n; i ++)
#define repb(i, n) for(int i = 1; i <= n; i ++)
#define repc(i, n) for(int i = 0; i < n; i ++)
#define lson (u << 1)
#define rson (u << 1 | 1)
#define gcd(a, b) __gcd(a, b)

const int N = 1e5 + 5;
int n, x, y;

void sol(int t, int sx, int sy, int x, int y)
{
    if(t == 0) return ;
    int mid = (pow(2, t)) / 2;
    if(x < sx + mid && y < sy + mid)
	{
		cout << sx + mid << ' ' << sy + mid << ' ' << 1 << endl;
		sol(t - 1, sx, sy, x, y), sol(t - 1, sx, sy + mid, sx + mid - 1, sy + mid);
		sol(t - 1, sx + mid, sy, sx + mid, sy + mid - 1), sol(t - 1, sx + mid, sy + mid, sx + mid, sy + mid);
	}
	else if(x < sx + mid)
	{
		cout << sx + mid << ' ' << sy + mid - 1 << ' ' <<  2 << endl;
		sol(t - 1, sx, sy, sx + mid - 1, sy + mid - 1), sol(t - 1, sx, sy + mid, x, y);
		sol(t - 1, sx + mid, sy, sx + mid, sy + mid - 1), sol(t - 1, sx + mid, sy + mid, sx + mid, sy + mid);
	}
	else if(y < sy + mid)
	{
		cout << sx + mid - 1 << ' ' << sy + mid << ' ' << 3 << endl;
		sol(t - 1, sx, sy, sx + mid - 1, sy + mid - 1), sol(t - 1, sx, sy + mid, sx + mid - 1, sy + mid);
		sol(t - 1, sx + mid, sy, x, y), sol(t - 1, sx + mid, sy + mid, sx + mid, sy + mid);
	}
	else
	{
		cout << sx + mid - 1 << ' ' << sy + mid - 1 << ' ' << 4 << endl;
		sol(t - 1, sx, sy, sx + mid - 1, sy + mid - 1), sol(t - 1, sx, sy + mid, sx + mid - 1, sy + mid);
		sol(t - 1, sx + mid, sy, sx + mid, sy + mid - 1), sol(t - 1, sx + mid, sy + mid, x, y);
	}
}

void solve()
{
    n = read;
    x = read, y = read;
    sol(n, 1, 1, x, y);
}

int main()
{
    int T = 1;
    while(T -- ) solve();
    return 0;
}

后记

感觉难度还好,但是画图的时候一定要细心!

posted @ 2024-03-03 19:33  浮光流年  阅读(28)  评论(0编辑  收藏  举报