【2020 杭電多校】第7場 Increasing and Decreasing 構造
阿新 • • 發佈:2020-08-12
題意
給出 \(n\) , \(x\) , \(y\) ,問是否可以構造出一個長度為 \(n\) 的全排列,滿足以下條件:
- 最長遞增子序列的長度等於 \(x\) ,
- 最長遞減子序列的長度等於 \(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; } /* */