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 }