構造一個 1..n 的排列使得他的 最長單調子序列 恰好長度為 k
最長單調子序列 是指這個子序列單調遞增或單調遞減
LIS 為 longest increasing subsequnce LDS 為 longest decreasing subsequnce
LIS 為 longest increasing subsequnce
LDS 為 longest decreasing subsequnce
ans=max{len(LIS)len(LDS)
發現說要想使答案控制得很好需要使得 len(LIS) 跟 len(LDS) 取得平衡
例如 n=9,k=3 那我必須使得 len(LIS) = len(LDS) = 3
使得 LIS 和 LDS 不互相影響
[3,2,1―,6,5,4―,9,8,7―]
紅色為其中一個 LIS 底線為 LDS
proof: k<n 無解
proof:
k<n 無解
鴿籠原理 若有 n 個籠子和 n+1 隻鴿子,所有的鴿子都被關在鴿籠裡,那麼至少有一個籠子有至少 2 隻鴿子。
鴿籠原理
那接著分以下 case:
故假設錯誤,代表 len(LIS),len(LDS) 長度會比 k 大,代表 k<n 無解
#include <bits/stdc++.h> #define int long long #define pii pair<int, int> #define pb push_back #define mk make_pair #define F first #define S second #define ALL(x) x.begin(), x.end() using namespace std; using PQ = priority_queue<int, vector<int>, greater<int>>; const int INF = 2e18; const int maxn = 3e5 + 5; const int M = 1e9 + 7; int n, m, k; // 向下取整 int ifloor(int a, int b){ if(b < 0) a *= -1, b *= -1; if(a < 0) return (a - b + 1) / b; else return a / b; } // 向上取整 int iceil(int a, int b){ if(b < 0) a *= -1, b *= -1; if(a > 0) return (a + b - 1) / b; else return a / b; } void init() { cin >> n >> k; } // 開根號 int sqt (int x) { int tmp = sqrt (x); if (tmp * tmp < x) tmp++; return tmp; } void solve() { m = sqt (n); if (k < m) { cout << "IMPOSSIBLE\n"; return; } int num = iceil(n, k); // 分幾段 // 每一段有 k 個東西, 共 n/k 段 int pre = 0, start = k; for (int i = 0; i < num; i++) { // 3 2 1 6 5 4 9 8 7 for (int j = start; j > pre; j--) { cout << j << " "; } pre = start; start += k; if (start > n) start = n; // 太大變 n } cout << "\n"; } signed main() { // ios::sync_with_stdio(0); // cin.tie(0); int t = 1; cin >> t; while (t--) { init(); solve(); } }
題解
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up