codeforces B. Sereja and Stairs 解题报告

时间:2023-03-10 04:12:59
codeforces   B. Sereja and Stairs   解题报告

题目链接:http://codeforces.com/problemset/problem/381/B

题目意思:给定一个m个数的序列,需要从中组合出符合楼梯定义

a1 < a2 < ... < ai - 1 < ai > ai + 1 > ... > a|a| - 1 > a|a|.

的最长序列。

思路不复杂,先把输入的序列按从小到大排序,然后依次挑出不相同的数(顺挑)。接着倒序再挑出不相同的数(可以与顺挑时的数相同)。有一个要注意的地方是,挑出的那些数的位置需要标记下,防止逆挑的时候重复挑。

 #include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std; const int maxn = 1e5 + ;
int a[maxn], vis[maxn], res[maxn]; int main()
{
int i, j, k, n, cnt;
while (scanf("%d", &n) != EOF)
{
for (i = ; i < n; i++)
scanf("%d", &a[i]);
sort(a, a+n);
memset(vis, , sizeof(vis)); vis[] = ; //第0个位置已取数
j = ;
res[j++] = a[];
cnt = ;
for (i = ; i + < n; )
{
k = i+;
while (a[k] == a[i]) // 有可能有多个a[i]的数,要跳过
k++;
if (k >= n) // 上一步中的k++有可能越界
break;
if (!vis[k]) // 防止逆挑时重复挑
{
res[j++] = a[k];
vis[k] = ; // 该位置已用
cnt++;
}
i = k;
if (a[k] == a[n-]) // 等于最大的那个数时跳出
break;
}
for (i = n-; i- >= ; )
{
k = i-;
while (a[k] == a[i])
k--;
if (k < )
break;
if (!vis[k])
{
res[j++] = a[k];
vis[k] = ; // 该位置已用
cnt++;
}
i = k;
if (a[k] == a[])
break;
}
printf("%d\n", cnt);
for (i = ; i < j; i++)
printf("%d ", res[i]);
printf("\n");
}
return ;
}

改进后的代码:

 #include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std; const int maxn = + ;
int cnt[maxn]; int main()
{
int i, m, sum, tmp, maxb;
while (scanf("%d", &m) != EOF)
{
memset(cnt, , sizeof(cnt));
sum = ;
maxb = -;
for (i = ; i < m; i++)
{
scanf("%d", &tmp);
cnt[tmp]++;
if (cnt[tmp] == || cnt[tmp] == )
sum++;
if (maxb < tmp)
maxb = tmp;
}
if (cnt[maxb] >= )
sum--;
printf("%d\n", sum);
for (i = ; i <= maxb; i++)
{
if (cnt[i])
{
printf("%d ", i);
cnt[i]--;
}
}
for (i = maxb-; i >= ; i--)
{
if (cnt[i])
printf("%d ", i);
}
printf("\n");
}
return ;
}