首页 > 代码库 > CodeForces Round #283 Div.2

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\n", 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 Queue11 {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是否小于b18     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然后全部变为前导050             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("\n");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\n", 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         else54         {55             for(int j = 0; j < n-1; ++j)56             {57                 if(equ[j] && table[j][i] < table[j+1][i])//更新equ58                     equ[j] = false;59             }60         }61     }62 63     printf("%d\n", ans);64 65     return 0;66 }
代码君

 

CodeForces Round #283 Div.2