JOID1T1 Sol瞎写

皎月半洒花

2020-03-20 23:55:20

Personal

想不到吧,我这种老年选手还去打JOI( 明天可能会鸽。不得不说JOI的题跟AGC的题画风确实不一样,可能不适合我这种才疏学浅的选手.jpg 然后写一个Sol证明我打过233 T2、3都不会,别骂了别骂了QAQ ____ 题意:给定等长的两个偶长度序列 $A,B$ 。从这两个序列中各挑出一半互不相同的位置组成一个新的序列,使之满足从头到尾单调。 首先一个自然的想法,因为是后面限制前面所以要倒着做。然后就是自然的 $dp$ (你问我为什么这个是自然的,我只能说在尝试暴力/带悔贪心/建图都GG了之后,这个就变成自然的了)。$dp$ 分两部分,一部分用来确定所有状态是否合法,一部分用来最优化可以补上的数值。 那么 $f_{i,0/1}$ 表示**后** $i$ 个元素,在第 $i$ 个元素填 $0/1$ 的时候是否合法。转移是 `general` 的。然后考虑根据这个 $dp$,显然可以构造出一种答案,但是这种答案不保证每个都选了 $n$ 个,但是这个答案可以保证每个位置的数都尽量选最小的。在这个答案里,不妨记 $0$ 的个数与 $1$ 的个数的差是 $k$。 然后考虑如何去调整这个序列使之合法。再定义 $dp$ ,$g_{i,0/1}$ 表示当第 $i$ 个位置的状态为 $0/1$ 时,$i\sim n$ 在满足 $1\sim _{i-1}$ 的约束时,这些位置最多可以提供多少差值。 那么考虑根据 $g$ 的定义,最后的答案一定可以转化成改变一个后缀。于是直接去找这个差值即可。复杂度 $O(n)$ 。 ```cpp using namespace std ; #define Trump return Output(), 0 const int N = 1000010 ; int n ; int cnt ; int res[N] ; int ans[N] ; int f[N][2] ; int g[N][2] ; int base[N][2] ; void Output(){ for (int i = 1 ; i <= n ; ++ i) printf("%c", (char)('A' + ans[i])) ; } int getsign(int x){ return x ? 1 : -1 ; } int main(){ cin >> n ; n *= 2 ; for (int i = 0 ; i <= n ; ++ i) g[i][0] = g[i][1] = -1000001 ; for (int j = 0 ; j < 2 ; ++ j) for (int i = 1 ; i <= n ; ++ i) scanf("%d", &base[i][j]) ; f[n][0] = f[n][1] = 1 ; int p = n - 1 ; for (int i = p ; i >= 1 ; -- i) for (int j = 0 ; j <= 1 ; ++ j) for (int k = 0 ; k <= 1 ; ++ k){ if (!f[i + 1][k]) continue ; if (base[i][j] <= base[i + 1][k]) f[i][j] |= f[i + 1][k] ; } if (!(f[1][1] or f[1][0])) return puts("-1"), 0 ; ans[++ cnt] = ((base[1][0] >= base[1][1]) and (f[1][1])) ? 1 : 0 ; for (int i = 2 ; i <= n ; ++ i){ if (base[i][0] < base[i][1]){ ++ cnt ; int q = cnt - 1 ; ans[cnt] = (base[i - 1][ans[q]] > base[i][0]) ? 1 : 0 ; } else { ++ cnt ; int q = cnt - 1 ; ans[cnt] = (base[i - 1][ans[q]] > base[i][1]) ? 0 : 1 ; } } //for (int i = 1 ; i <= n ; ++ i) cout << ans[i] << " " ; puts("") ; int t = 0, dif = 0 ; g[n][ans[n]] = 0 ; for (int i = 1 ; i <= n ; ++ i) t += getsign(ans[i]) ; if (!t) Trump ; g[n][!ans[n]] = 2 * getsign(!ans[n]) * getsign(t < 0) ; for (int i = p ; i >= 1 ; -- i) for (int j = 0 ; j <= 1 ; ++ j){ dif = (ans[i] ^ j) ? (2 * getsign(!ans[i]) * getsign(t < 0)) : 0 ; for (int k = 0 ; k <= 1 ; ++ k){ if (g[i + 1][k] == -1000001) continue ; if (base[i + 1][k] < base[i][j]) continue ; if (base[i - 1][ans[i - 1]] > base[i][j]) continue ; g[i][j] = max(g[i][j], g[i + 1][k] + dif) ; } } cnt = 0 ; int pq ; res[++ cnt] = pq = (bool)(g[1][1] > g[1][0]) ; if (max(g[1][0], g[1][1]) < (getsign(t > 0) * t)) return puts("-1"), 0 ; for (int i = 1 ; i < n ; ++ i){ dif = (ans[i] ^ pq) ? (2 * getsign(!ans[i]) * getsign(t < 0)) : 0 ; for (int k = 0 ; k <= 1 ; ++ k){ if (base[i + 1][k] < base[i][pq]) continue ; if (g[i + 1][k] + dif == g[i][pq]) { res[++ cnt] = pq = k ; break ; } } } //for (int i = 1 ; i <= n ; ++ i) cout << res[i] << " " ; puts("") ; for (int i = 1 ; i <= n ; ++ i) if (g[i][res[i]] == (getsign(t > 0) * t)){ for (int j = i ; j <= n ; ++ j) ans[j] = res[j] ; Trump ; } Trump ; } ```