Codeforces Round #831 (Div. 1 + Div. 2) D. Knowledge Cards 解题报告

原题链接:

Problem - 1740D - Codeforces (Unofficial mirror by Menci)

题目描述:

Pak Chanek, a renowned scholar, invented a card puzzle using his knowledge. In the puzzle, you are given a board with nn rows and mm columns. Let (r,c)(r,c) represent the cell in the rr-th row and the cc-th column.

Initially, there are kk cards stacked in cell (1,1)(1,1). Each card has an integer from 11 to kk written on it. More specifically, the ii-th card from the top of the stack in cell (1,1)(1,1) has the number aiai written on it. It is known that no two cards have the same number written on them. In other words, the numbers written on the cards are a permutation of integers from 11 to kk. All other cells are empty.

You need to move the kk cards to cell (n,m)(n,m) to create another stack of cards. Let bibi be the number written on the ii-th card from the top of the stack in cell (n,m)(n,m). You should create the stack in cell (n,m)(n,m) in such a way so that bi=ibi=i for all 1≤i≤k1≤i≤k.

In one move, you can remove the top card from a cell and place it onto an adjacent cell (a cell that shares a common side). If the target cell already contains one or more cards, you place your card on the top of the stack. You must do each operation while satisfying the following restrictions:

  • Each cell other than (1,1)(1,1) and (n,m)(n,m) must not have more than one card on it.
  • You cannot move a card onto cell (1,1)(1,1).
  • You cannot move a card from cell (n,m)(n,m).

Given the values of nn, mm, kk and the array aa, determine if the puzzle is solvable.

Input

Each test contains multiple test cases. The first line contains an integer tt (1≤t≤2⋅1041≤t≤2⋅104) — the number of test cases. The following lines contain the description of each test case.

The first line of each test case contains three integers nn, mm, and kk (3≤n,m≤1063≤n,m≤106, nm≤106nm≤106, 1≤k≤1051≤k≤105) — the size of the board and the number of cards.

The second line of the test case contains kk integers a1,a2,…,aka1,a2,…,ak — the array aa, representing the numbers written on the cards. The values of aa are a permutation of integers from 11 to kk.

It is guaranteed that the sum of nmnm and kk over all test cases do not exceed 106106 and 105105 respectively.

Output

For each test case, output "YA" (without quotes) if it is possible and "TIDAK" (without quotes) otherwise, which mean yes and no in Indonesian respectively.

You can output "YA" and "TIDAK" in any case (for example, strings "tiDAk", "tidak", and "Tidak" will be recognised as a negative response).

题目大意:

给定一个 n∗m 的矩阵,在(1,1)的位置放置了 k 个棋子,k个棋子是 1−k 的排列,给定这些棋子从上到下放置的顺序。每次可以移动最顶端的一个棋子到相邻的位置,棋子除了在起点和终点都不能重叠,并且不可把其他位置的棋子移动回(1,1)。求 k 个棋子最终能否在(n,m)处从上到下以 1−k 的顺序叠放好。

解题思路以及代码:

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define lowbit(x) ((x) & (-x))
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e6 + 10;
const int INF = 0x3fffffff;
int n, m, k, a[maxn], BIT[maxn];

/*
    思路:我们把不能一次放到终点的棋子先放在一边。然后每次遇到能放的棋子就直接过去。我们能够停放的位置一共有n*m-2个,
    我们首先会想,是不是必须让出一条路才能让棋子通过。但事实是只要有一个空位,就一定可以通过调整到达终点。
    所以我们每操作一个棋子之前检查棋盘上除(1,1)和(n,m)以外是否有大于等于n*m-3枚棋子,是的话则无解。
    我采取的实现方式是用树状数组来维护,getSum(x)为当前小于等于x的个数,即移动x之前,当前棋盘除(1,1)和(n,m)以外棋子的数量。
*/

int getSum(int x)
{
    int sum = 0;
    for (int i = x; i; i -= lowbit(i))
    {
        sum += BIT[i];
    }
    return sum;
}

void update(int x, int v)
{
    for (int i = x; i <= k; i += lowbit(i))
    {
        BIT[i] += v;
    }
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cout << fixed;
    cout.precision(18);

    int t;
    cin >> t;
    while(t--)
    {
        cin >> n >> m >> k;
        memset(BIT, 0, sizeof(int) * (k + 10));
        bool flag = true;
        for (int i = 1, x; i <= k; i++)
        {
            cin >> x;
            if(getSum(x) >= n * m - 3)
                flag = false;
            update(x, 1);
        }
        if(flag)
            cout << "YA" << endl;
        else
            cout << "TIDAK" << endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值