Floor Tiles (牛客多校2 A)

进入博客阅读体验更佳:Floor Tiles (牛客多校2 A) | 付诺の小站 (funuo0728.github.io)

Floor Tiles

题目大意


你有两种类型的地砖:

上面一种类型为A,下面一种类型为B,现在一个n \times m(1 \le n,m \le800)的矩阵,最初会在某一格上放置一个A或B类型的地砖,你需要填满剩下n \times m - 1格,问是否有一种摆放方式使得恰好能使其显示k(1 \le k \le 2 \cdot nm)条曲线,若有,请输出Yes,并给出摆放方案,否则,输出No。

共有T(1 \le T \le 10 ^ 5)次询问。

解题思路


注意到无论 N, M 是多少,矩阵的结构如何,从整个二维矩阵边缘进入 的曲线最终一定会从整个二维矩阵边缘出去,不可能进入其内部的任何 一个环;

边缘的“线头”一共有 2(N + M) 个,所以这样的曲线数目为 2(N+M) 2 = N + M 个;

对于一个大小为 N \times M 的平面,其曲线总数为 N + M+ 平面结构 内部环的数目。

接下来考虑如何造环,可以发现仅有A ~ B \\ B ~ A的情况才会构成一个环,

当矩阵左上角为A时,曲线个数的取值范围为[n + m, \lfloor \frac{nm -n -m + 2}{2} \rfloor + n + m];

当矩阵左上角为B时,曲线个数的取值范围为[n + m, \lfloor \frac{nm -n -m + 1}{2} \rfloor + n + m];

先将矩阵中所有方块赋成已放置方块的样式,然后在一行一行遍历构造环即可。

参考代码

#include <bits/stdc++.h>
#define maxn 810
#define int long long
using namespace std;
const double eps = 1e-8;
int n, m, k;
char g[maxn][maxn];
​
void tt() {
    cout << "Yes\n";
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j)  cout << g[i][j];
        cout << '\n';
    }
}
​
void check() {
    int res = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if(g[i][j] == 'A' && g[i + 1][j + 1] == 'A' && g[i + 1][j] == 'B' && g[i][j + 1] == 'B')  ++res;
        }
    }
    cout << res << '\n';
}
​
void op1(char x) {
    int l = n + m, r = (n * m - n - m + 2) / 2 + n + m;
    if(k < l || k > r) {
        cout << "No\n";
        return ;
    }
    k -= n + m;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            g[i][j] = x;
        }
    }
    for (int i = 1; i < n && k; ++i) {
        for (int j = (i & 1) ? 1 : 2; j + 1 <= m && k; j += 2, --k) {
            g[i][j] = g[i + 1][j + 1] = 'A';
            g[i + 1][j] = g[i][j + 1] = 'B';
        }
    }
    tt();
}
​
void op2(char x) {
    int l = n + m, r = (n * m - n - m + 1) / 2 + n + m;
    if(k < l || k > r) {
        cout << "No\n";
        return ;
    }
    k -= n + m;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            g[i][j] = x;
        }
    }
    for (int i = 1; i < n && k; ++i) {
        for (int j = (i & 1) ? 2 : 1; j + 1 <= m && k; j += 2, --k) {
            g[i][j] = g[i + 1][j + 1] = 'A';
            g[i + 1][j] = g[i][j + 1] = 'B';
        }
    }
    tt();
    // check();
}
​
​
void solve() {
    cin >> n >> m >> k;
    int x, y;  char s;
    cin >> x >> y >> s;
    if((x + y) % 2 == 0 && s == 'A' || ((x + y) & 1) && s == 'B')  op1(s);
    else  op2(s);
}
​
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);  cout.tie(0);
    int t = 1;  cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}
  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值