P13792

· · 题解

题意简述:有 n 张五种花色的牌 S,W,E,R,C,其中花色 C 的牌是王牌。每次操作可以将一张牌插入两张牌之间,需要确定一种花色间的顺序,使得在进行若干次操作后,整副牌的花色按照该种顺序排列,且同一花色内的牌按照数字大小升序排序,特别地,王牌花色需要排在最后一个。求最小的操作次数。

**思路**:考虑将“插入操作”当做“删除操作”,因为在最优策略下,一张牌一定在一次插入后就不会第二次进行插入,且不会对剩余牌造成影响,等价于直接删除。 题目中需要按照某种顺序排列花色,观察到需要排序的花色数量极其少,只有 $4$ 种,因此直接考虑 $4!$ 暴力枚举全排列。 由于需要以花色和数字为关键字对牌进行排序,因此考虑将这两个要素融合成牌的一个权重,依据权重进行升序排序。不难想到用花色在全排列中的位次 $\times n$ 后加上数字作为权重,这样既兼顾了花色的升序,又兼顾了数字的升序,还能避免不同花色间串号(因为 $V\le n$,所以不同花色间的权重一定不会串)特别地,需要保证花色为 `C` 的牌权重为 $4n+V$,保证王牌花色的牌的权重高于其他花色的一切牌。 因为我们需要最小化删除的牌个数,又要使得所有牌的权重升序排序,所以考虑在权重数组 $w$ 上求 LIS 得到长度 $l$ 后用 $n-l$ 得到最小删除数量,只需要在所有排列中求出 $n-l$ 的最小值并输出即可。 枚举全排列并修改权重的时间复杂度为 $\mathcal O(4!n)$,求出 LIS 的时间复杂度为 $\mathcal O(4!n\log n)$,因此时间复杂度取 $\mathcal O(n\log n)$,可以通过本题。 **AC CODE**: [submission](https://www.luogu.com.cn/record/304797927)。 ```cpp #include<bits/stdc++.h> #define y0 y_0 #define y1 y_1 #define fi first #define se second #define endl '\n' #define vec vector #define em emplace #define pb push_back #define eb emplace_back #define lc(x) x << 1 #define rc(x) x << 1 | 1 #define lowbit(x) ((x) & (-(x))) #define popcount(x) __builtin_popcount(x) #define ckmin(x, y) x = (x) <= (y) ? (x) : (y) #define ckmax(x, y) x = (x) >= (y) ? (x) : (y) #define debug(x) cerr << #x << " = " << x << endl #define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0) using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; typedef pair<ll, ll> pll; // #define MultiTest const double EPS = 1e-8; const int INF = 0x3f3f3f3f; const ll LINF = 0x3f3f3f3f3f3f3f3f; const int N = 1e5 + 5; int n, w[N], d[N]; pii c[N]; int get(char ch) { switch(ch) { case 'S': return 1; case 'W': return 2; case 'E': return 3; case 'R': return 4; case 'C': return 5; } } int getLIS() { memset(d, 0x3f, sizeof d); int len = 0; d[0] = 0; for(int i = 1; i <= n; i++) { if(w[i] > d[len]) d[++len] = w[i]; else { int x = lower_bound(d + 1, d + 1 + len, w[i]) - d; d[x] = w[i]; } } return len; } void solve() { cin >> n; for(int i = 1; i <= n; i++) { char ch; cin >> ch; int num; cin >> num; c[i] = {get(ch), num}; if(c[i].fi == 5) w[i] = 4 * n + num; } int p[5] = {0, 1, 2, 3, 4}, maxlis = 0; do { for(int i = 1; i <= 4; i++) { for(int j = 1; j <= n; j++) { if(c[j].fi == p[i]) w[j] = (i - 1) * n + c[j].se; } } ckmax(maxlis, getLIS()); } while(next_permutation(p + 1, p + 5)); cout << n - maxlis << endl; } int main() { IOS; // freopen("a.in", "r", stdin); // freopen("a.out", "w", stdout); int T = 1; #ifdef MultiTest cin >> T; #endif while(T--) solve(); return 0; } ```