CodeForces 58C Trees

  原题传送:http://codeforces.com/problemset/problem/58/C

  很容易想到很不高效的 O(n2) 的枚举算法,这种算法中进行非常多不必要和重复的计算。对题目给的数据范围显然会T。

  题目中要求的是序列间隔1进行前半段的上升与后半段的下降,那么,以下两点很容易知道:

    1.  整个序列可以由序列的任一个数来决定

    2.  至少有一个数是不被改变的

  那么,我们只需要求出在序列的某种合法状态下,所给序列中最多的合法元素个数 m,则 n-m 就是所求。这里我线性时间扫一遍每一个元素,同时计算出当前值不改变情况下第一个元素的值 x(说穿了,就是序列的每一个元素都可以转换为第一个元素的值),那么 d[x]++( d 数组为计数数组)。

View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 const int maxn = 100000 + 10;
 5 
 6 int a[maxn], d[maxn];
 7 
 8 int main()
 9 {
10     int n;
11     while(scanf("%d", &n) == 1)
12     {
13         for(int i = 1; i <= n; i ++)
14             scanf("%d", &a[i]);
15         memset(d, 0, sizeof d);
16         int k = n / 2 + n % 2;
17         for(int i = 1; i <= k; i ++)
18         {
19             if(a[i]-i+1 > 0)
20                 d[a[i]-i+1] ++;
21         }
22         for(int i = n; i > k; i --)
23             if(a[i]+i-n>0)
24                 d[a[i]+i-n] ++;
25         int m = -1;
26         for(int i = 1; i <= 100000; i ++)
27             m = std::max(m, d[i]);
28         printf("%d\n", n - m);
29     }
30     return 0;
31 }
原文地址:https://www.cnblogs.com/huangfeihome/p/2824709.html