题解 CF1157F 【Maximum Balanced Circle】

SIGSEGV

2019-06-23 08:14:46

Solution

首先,来个桶排序,令$t_i$表示输入序列中$i$出现的次数 然后令$dp_i$表示一个环上最大数为$i$的环的长度 于是,我们开始愉快地分类讨论(其实这只能算递推,不能算dp) 1. $a_{i-1}=0$ 只能新开一个环,$dp_i=a_i$ 2. $a_{i-1}>1$ 由于$i-1$在环中一定连续(它是当前环中最大值),此时我们可以在构造环时将所有$i$连续地插入$i-1$组成的环的部分内(即插入前环的一部分为$i-1,i-1,i-1,...,i-1$插入后环的一部分为$i-1,i-1,...,i,i,i,...,i-1$) 这样我们就可以保证插入合法,$dp_i=a_i+dp_{i-1}$ 3. $a_{i-1}=1$,此时我们可以构造新的环$C$,$C_{1..a_i}=i$且$C_{a_i+1}=i-1$,此时这个环也是合法的,$dp_i=a_i+1$ 同时,递推时用$start$数组记录环的起点,方便输出 输出时就按dp时的构造方法 注意:文字中的$t$数组对应代码中的$a$ ```cpp #include <bits/stdc++.h> using namespace std; const int N = 200005; int n,a[N],dp[N],start[N]; void output(int pos,int top) { for (int i = 1;i < a[pos];i++) printf("%d ",pos); if (pos < top) output(pos + 1,top); printf("%d ",pos); } int main () { scanf("%d",&n);int tmp,mx = -1; for (int i = 1;i <= n;i++) scanf("%d",&tmp),a[tmp]++,mx = max(mx,tmp); for (int i = 1;i <= mx;i++) if (a[i]) { if (!a[i - 1] || (a[i - 1] == 1 && dp[i - 1] != 1)) dp[i] = a[i] + !!a[i - 1],start[i] = i - !!a[i - 1]; else dp[i] = a[i] + dp[i - 1], start[i] = (start[i - 1] ? start[i - 1] : i); } int ans = -1,pos = 0; for (int i = 1;i <= mx;i++) if (dp[i] > ans) {ans = dp[i];pos = i;} printf("%d\n",ans); if (ans == 1) printf("%d",pos); else output(start[pos],pos); return 0; } ```