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;
}
后记
感觉难度还好,但是画图的时候一定要细心!