CodeForces Round #283 Div.2

A. Minimum Difficulty

题意:

有一个递增序列a,现在要去掉除了第一项和最后一项元素外的某一项,使新数列中相邻元素之差的最大值最小。

分析:

先求出原序列a中,相邻两项元素之差的最大值m。

枚举去掉ai,则新序列相邻元素差的最大值为max{ m, ai+1 - ai },然后记录最小值即可。

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 const int maxn = 100 + 10;
 6 int a[maxn];
 7 
 8 int main(void)
 9 {
10     int n;
11     scanf("%d", &n);
12     for(int i = 0; i < n; ++i) scanf("%d", &a[i]);
13     int max1 = 0;
14     for(int i = 0; i < n-1; ++i) max1 = max(max1, a[i+1]-a[i]);
15 
16     int ans = 10000;
17     for(int i = 1; i < n-1; ++i) ans =min(ans, max(max1, a[i+1]-a[i-1]));
18 
19     printf("%d
", ans);
20 
21     return 0;
22 }
代码君

B. (贪心)Secret Combination

题意:

给出一个n(≤1000)位数字,有下面两种操作:

  1. 将每位数字都自增1,如果是9的话变为0.(注意,每个数位上的数字都是单独操作的互不影响,没有相互之间的进位)
  2. 将每位数字向右移一位,最右边的数字则移到最左边

求经过若干次操作,n能变为的最小数字。

分析:

首先我们想一下,最小的数字会有什么特点?那就是他前面会有很多前导0

可以把几个连续相同的数字通过操作1加上某个数使其全部变为0,然后通过操作2将其变为前导0

比如:325556,可以进行5次操作1变为870001,然后进行4次操作2,变为000187.

因此,可以预处理n,求出最长连续数字,如果对应有多个相同长度的连续数字,则记录下他们的长度和位置,方便在后面进行比较。

还要注意的是:由于操作2的特性,要考虑到首尾相接也可能出现相同连续的数字,所以我们可以对数组的索引模n取余或者将数字适当延长两倍或三倍。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 using namespace std;
 5 
 6 const int maxn = (1000 + 10)*3;
 7 char s[maxn], s1[maxn], s2[maxn];//输入的数字,当前最小数字,要比较的数字
 8 int n;
 9 
10 struct Queue
11 {
12     int pos, len;
13     Queue(int p=0, int l=0):pos(p), len(l) {}
14 }q[maxn]; //记录下连续相同数字的其实位置和个数
15 
16 bool lessthan(char* a, char* b)
17 {//比较数字a是否小于b
18     int i = 0;
19     while(i < n && a[i] == b[i]) i++;
20     if(i >= n) return false;
21     return a[i] < b[i];
22 }
23 
24 int main()
25 {
26     scanf("%d", &n);
27     scanf("%s", s);
28     strcpy(s1, s);
29     for(int i = 0; i < n; ++i) s[i+n] = s[i+2*n] = s[i];
30     int lx = 1, p = 0;
31     for(int i = 0; i < 2*n; i++)
32     {
33         int st = i;
34         int temp = 1;
35         while(i < 2*n-1 && s[i] == s[i+1])
36         {
37             temp++;
38             i++;
39         }
40         q[p++] = Queue(st, i+1-st);
41         if(temp > lx)
42             lx = temp;  //记录最长相同数字
43     }
44 
45     for(int i = 0; i < p; ++i)
46     {
47         if(q[i].len == lx)
48         {
49             int add = ('9' + 1 - s[q[i].pos]) % 10;//将这些相同数字加上add然后全部变为前导0
50             for(int j = 0; j < n; ++j)
51             {
52                 s2[j] = '0' + (s[q[i].pos+j]-'0'+add)%10;
53             }
54             if(lessthan(s2, s1))
55             {
56                 for(int k = 0; k < n; ++k) s1[k] = s2[k];
57             }
58         }
59     }
60 
61     for(int i = 0; i < n; ++i) printf("%c", s1[i]);
62     printf("
");
63 
64     return 0;
65 }
代码君

C. (字符串、贪心)Removing Columns

题意:

给出n×m(n,m≤100)的字符矩阵,求最少去掉多少列,使得剩下的字符串从上到下是按字典序费递减排列的。

分析:

单独看一列:如果某个字母比它下面的字母要大,那么这一列一定不能作为最终字符串开头的一列。

从左往右扫,直到找到能作为最终字符串开头的一列c1为止。

则c1一定要保留,作为字符串的开头,贪心的理由是:

如果后面也有一列c2满足作为字符串的开头,则c1...c2...从上到下一定满足字典序的顺序,而且不会使去掉的列数变多。

选好字符串开头以后,继续往后扫描:

如果本来某一行的字符串小于下面的字符串,则后面无论接什么样的字符,这两个字符串大小关系不变。

如果原来某一行字符串等于下面一行的字符串,则后面接的字符也要满足大小关系。

 1 #include <cstdio>
 2 
 3 const int maxn = 100 + 10;
 4 bool bad[maxn], equ[maxn];//equ标记当前字符串中相邻两行是否相等
 5 //bad标记该列是否被去掉,作为答案的统计
 6 
 7 char table[maxn][maxn];
 8 
 9 int main()
10 {
11     //freopen("in.txt", "r", stdin);
12 
13     int n, m;
14     scanf("%d%d", &n, &m);
15     for(int i = 0; i < n; ++i) scanf("%s", table[i]);
16 
17     if(n <= 1)
18     {
19         puts("0");
20         return 0;
21     }
22 
23     int st = 0;//找到字符串的开头
24     for(; st < m; ++st)
25     {
26         int i;
27         for(i = 0; i < n-1; ++i)
28             if(table[i][st] > table[i+1][st])
29                 break;
30         if(i == n-1) break;
31     }
32     if(st == m)
33     {
34         printf("%d
", m);
35         return 0;
36     }
37 
38     int ans = st;
39     for(int i = 0; i < n-1; ++i)
40     {
41         if(table[i][st] == table[i+1][st])
42             equ[i] = true;
43     }
44     for(int i = st+1; i < m; ++i)
45     {
46         for(int j = 0; j < n-1; ++j)
47         {
48             if(equ[j] && table[j][i] > table[j+1][i])//只有原来字符串相等且后面接的字符不满足顺才去掉该列
49                 bad[i] = true;
50         }
51         if(bad[i])
52             ans++;//统计被去掉的行数
53         else
54         {
55             for(int j = 0; j < n-1; ++j)
56             {
57                 if(equ[j] && table[j][i] < table[j+1][i])//更新equ
58                     equ[j] = false;
59             }
60         }
61     }
62 
63     printf("%d
", ans);
64 
65     return 0;
66 }
代码君
原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4170872.html