成就:赛后在cf使用错误的贪心通过一题
成就:在cf上赛后提交hack数据
成就:在cf上赛后hack自己
题目大意
有一长度$n le 2 imes 10^5$的序列,要求判断是否能够划分为一个严格递增和一个严格递减的子序列并给出划分方案。
题目分析
错误的贪心
截止现在(4.22),这一种错误贪心尚可以通过此题。
算法流程:考虑处理出一个LIS和一个LDS,并检查剩下的元素是否为LDS/LIS.
这个算法在随机构造下是基本没问题的(因此跑了47000+组随机数据才rand出一组反例)。
事实上,如果枚举每一个LIS/LDS,这个做法就是显然正确的,但是复杂度会有相当影响(例如一个完全非法但是LIS/LDS非常多的数列)
清真dp
记$f_{i,0}$为:$i$处在一个上升子序列中,$1cdots i-1$的下降子序列最高为$f_{i,0}$;$f_{i,1}$同理。
这个状态显然是需要贪心取最大/最小的,那么这个转移就可以做到$O(1)$,相当高效。
1 #include<bits/stdc++.h> 2 const int maxn = 200035; 3 const int INF = 2e9; 4 5 int n,a[maxn],p[maxn][2],f[maxn][2]; 6 7 int read() 8 { 9 char ch = getchar(); 10 int num = 0, fl = 1; 11 for (; !isdigit(ch); ch=getchar()) 12 if (ch=='-') fl = -1; 13 for (; isdigit(ch); ch=getchar()) 14 num = (num<<1)+(num<<3)+ch-48; 15 return num*fl; 16 } 17 void print(int x, int c) 18 { 19 if (x > 1) print(x-1, p[x][c]); 20 printf("%d ",c); 21 } 22 int main() 23 { 24 n = read(); 25 for (int i=1; i<=n; i++) a[i] = read(); 26 f[1][0] = INF, f[1][1] = -INF; 27 for (int i=2; i<=n; i++) 28 { 29 f[i][0] = -INF, f[i][1] = INF; 30 if (a[i] > a[i-1]&&f[i][0] < f[i-1][0]) f[i][0] = f[i-1][0], p[i][0] = 0; 31 if (a[i] < a[i-1]&&f[i][1] > f[i-1][1]) f[i][1] = f[i-1][1], p[i][1] = 1; 32 if (a[i] > f[i-1][1]&&f[i][0] < a[i-1]) f[i][0] = a[i-1], p[i][0] = 1; 33 if (a[i] < f[i-1][0]&&f[i][1] > a[i-1]) f[i][1] = a[i-1], p[i][1] = 0; 34 } 35 if (f[n][0]!=-INF) puts("YES"), print(n, 0), exit(0); 36 if (f[n][1]!=INF) puts("YES"), print(n, 1), exit(0); 37 puts("NO"); 38 return 0; 39 }
END