1. 程式人生 > 實用技巧 >【2020 杭電多校】第7場 Increasing and Decreasing 構造

【2020 杭電多校】第7場 Increasing and Decreasing 構造

題目連結

題意

給出 \(n\) , \(x\) , \(y\) ,問是否可以構造出一個長度為 \(n\) 的全排列,滿足以下條件:

  1. 最長遞增子序列的長度等於 \(x\) ,
  2. 最長遞減子序列的長度等於 \(y\)

思路

構造 \(x\) 個塊,每個塊裡的數字都是遞減的,並且最長的塊長度要為 \(y\) ,由這個最長的塊構成最長遞減子序列。

只需第 \(i\) 塊的最大值小於第 \(i+1\) 塊的最小值,最長遞增子序列由這 \(x\) 個塊中的任意 \(x\) 個元素組成。

因為要保證字典序最小,儘可能使得前面的塊長度為 \(1\) ,並且第 \(i\) 塊只有 \(i\) 一個元素,也就是後面塊的長度儘可能的長。

考慮極限情況,除了最後一個長度為 \(y\) 的塊,其他塊的長度都為 \(1\) ,那麼需要 \(x-1+y\) 個數字

所有的塊長度都為 \(y\) ,需要 \(x\times y\) 個數字。

所以當 \(x+y-1 \leq n \leq x \times y\) 時才可以構造成功。

程式碼

#include <bits/stdc++.h>
#define fuck system("pause")
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int N = 2e5 + 10;

int tmp[N];
stack<int> s;
int main()
{
    int _;
    scanf("%d", &_);
    while (_--) {
        int n, x, y;
        scanf("%d%d%d", &n, &x, &y);
        if (n < x + y - 1 || n > 1LL * x * y) { 
            printf("NO\n");
            continue;
        }
        printf("YES\n");
        int cnt = 0;
        while (n > 0) {
            x--, tmp[++(cnt=0)] = n--;//拿出一個元素放到當前塊中
            while (n > x && cnt < y && n > 0) {//剩下的元素大於剩下塊的個數,接著往當前塊填
                tmp[++cnt] = n--;              //直到當前塊的元素個數等於 y
            }
            for (int i = cnt; i ; i--) {
                s.push(tmp[i]);
            }
        }
        while (!s.empty()) {
            printf("%d%c", s.top(), s.size() == 1 ? '\n' : ' ');
            s.pop();
        }
    }
    return 0;
}
/*
*/