标签:style blog http ar io color os sp for
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)位数字,有下面两种操作:
求经过若干次操作,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("\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 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\n", ans); 64 65 return 0; 66 }
标签:style blog http ar io color os sp for
原文地址:http://www.cnblogs.com/AOQNRMGYXLMV/p/4170872.html