ACM-ICPC 2015 Mid-Central Regional
题目链接
http://acm.uestc.edu.cn/#/problem/show/1358
MCPC2015的题目,CDOJ上是2016 UESTC ACM Summer Training
直接看题
Problem A ACM Contest Scoring
简单的模拟题,给出了OJ的提交记录,让你计算出AC数目和罚时
总的实现和2017河工大邀请赛A题差不多。
和那个相比,这个省去了记录每个人的情况并进行排序的过程;
另外也可以改进一下直接在线做。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main(){ 5 int t, penalty[256], ans1 = 0, ans2 = 0; 6 char id; 7 string s; 8 bool ac[256]; 9 memset(ac, 0, sizeof(ac)); 10 memset(penalty, 0, sizeof(penalty)); 11 while(cin >> t >> id >> s && t != -1){ 12 if(!ac[id]){ 13 if(s == "right"){ 14 ac[id] = true; 15 ans1 ++; 16 ans2 += penalty[id] + t; 17 }else 18 penalty[id] += 20; 19 } 20 } 21 cout << ans1 << ' ' << ans2; 22 return 0; 23 }
Problem C Dance Recital
给出若干字符串(仅由A-Z组成),询问前后两个字符串的相似字母个数。
对于这些字符串的所有排列,求一个最小排列使得上述询问的结果最小。
题目数据很小,只有10个字符串,直接暴力枚举可行(没错,next_permutation可以过)。
也可以用回溯法手写求排列的过程
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n, ans = 0x3f3f3f3f; 4 char s[12][30]; 5 int change[12][12], ns[12], id[12]; 6 7 int main(){ 8 scanf("%d", &n); 9 for(int i = 0; i < n; i++){ 10 scanf("%s", s[i]); 11 ns[i] = strlen(s[i]); 12 id[i] = i; 13 } 14 for(int i = 0; i < n; i++){ 15 for(int j = i+1; j < n; j++){ 16 int tot = 0; 17 for(int k1 = 0, k2 = 0; k1 < ns[i] && k2 < ns[j]; ){ 18 if(s[i][k1] == s[j][k2]) 19 k1++, k2++, tot++; 20 else if(s[i][k1] < s[j][k2]) 21 k1++; 22 else k2++; 23 } 24 change[i][j] = change[j][i] = tot; 25 } 26 } 27 while(next_permutation(id, id+n)){ 28 int cur = 0; 29 for(int i = 0; i < n-1; i++) cur += change[id[i]][id[i+1]]; 30 ans = min(ans, cur); 31 } 32 printf("%d", ans); 33 return 0; 34 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n, ans; 4 char s[12][30]; 5 int change[12][12], ns[12]; 6 bool vis[12]; 7 int id[12]; 8 9 void dfs(int k){ 10 if(k == n){ 11 int cur = 0; 12 for(int i = 0; i < n-1; i++) cur += change[id[i]][id[i+1]]; 13 ans = min(ans, cur); 14 }else 15 for(int i = n-1; i >= 0; i--) 16 if(!vis[i]){ 17 id[k] = i; 18 vis[i] = true; 19 int cur = 0; 20 if(k > 1){ 21 for(int i = 0; i < k-1; i++) cur += change[id[i]][id[i+1]]; 22 if(cur < ans) dfs(k+1); 23 }else dfs(k+1); 24 vis[i] = 0; 25 } 26 } 27 28 int main(){ 29 scanf("%d", &n); 30 for(int i = 0; i < n; i++) scanf("%s", s[i]); 31 for(int i = 0; i < n; i++) ns[i] = strlen(s[i]); 32 for(int i = 0; i < n; i++){ 33 for(int j = i+1; j < n; j++){ 34 int tot = 0; 35 for(int k1 = 0, k2 = 0; k1 < ns[i] && k2 < ns[j]; ){ 36 if(s[i][k1] == s[j][k2]) 37 k1++, k2++, tot++; 38 else if(s[i][k1] < s[j][k2]) 39 k1++; 40 else k2++; 41 } 42 change[i][j] = change[j][i] = tot; 43 } 44 } 45 memset(vis, 0, sizeof(vis)); 46 memset(id, -1, sizeof(id)); 47 ans = 0x3f3f3f3f; 48 dfs(0); 49 printf("%d", ans); 50 return 0; 51 }
Problem D Hidden Password
给出两个字符串s1和s2,检查s1中的每一个字符是不是按约定顺序依次出现在s2中。
首先看s1的所有字符中,在s2中第一个出现的。
如果它不是s1最前面的字符的话,FAIL。
接着去掉s1第一个字符,对新的字符串继续进行上述操作。
实现的很乱,标准题解有相当好的STL解法。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main(){ 5 char pwd[10], str[50]; 6 char set[255], vis[255], flag = true; 7 int i, j; 8 memset(set, 0, sizeof(set)); 9 memset(vis, 0, sizeof(vis)); 10 scanf("%s%s", pwd, str); 11 int np = strlen(pwd), ns = strlen(str); 12 for(i = 0; i < np; i++) set[pwd[i]]++; 13 14 for(i = 0, j = 0 ; i < ns; i++){ 15 // printf("\n%d %d %c %d %c %d ", i, j, str[i], set[str[i]], pwd[j], set[pwd[j]]); 16 if(set[str[i]] > 0){ 17 if(str[i] != pwd[j]){ 18 // printf(" fail "); 19 flag = false; 20 break; 21 } 22 set[str[i]]--; 23 j++; 24 // if(set[pwd[j]] == false) set[pwd[j]] = true; 25 } 26 } 27 if(j < np) flag = false; 28 printf("%s", flag ? "PASS" : "FAIL"); 29 return 0; 30 }
Problem F Line Them Up
检查若干个名字是不是严格升序排列或者严格降序排列
有很多种想法,例如看前后两个的strcmp值是不是一致的(一致即有序,此时需要判断一下是1还是-1来确定是不是升序)。
或者排序后看看是不是和原来的是一致的,或者是相反的(时间复杂度稍高)。
或者各种脑洞写法。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main(){ 5 vector<string> ord1, ord2; 6 int n; 7 string s; 8 cin >> n; 9 for(int i = 0; i < n; i++){ 10 cin >> s; 11 ord1.push_back(s); 12 ord2.push_back(s); 13 } 14 sort(ord1.begin(), ord1.end()); 15 bool isInc = true, isDec = true; 16 for(int i = 0, j = n-1; i < n; i++, j--){ 17 if(ord1[i].compare(ord2[i]) != 0) isInc = false; 18 if(ord1[i] != ord2[j]) isDec = false; 19 } 20 if(isInc && !isDec) s = "INCREASING"; 21 if(!isInc && isDec) s = "DECREASING"; 22 if(!isInc && !isDec) s = "NEITHER"; 23 cout << s; 24 return 0; 25 }
Problem H Pyro Tubes
给出若干个整数(升序),对于第i个整数,看它后面有多少个和它在二进制上相差在2以内的整数,计算出它们个数。
最省事的想法就是暴力法O(n2),计算两个数的Xor值,看这个值里面有几个1,但显然TLE。
暴力的卡点在于计算Xor结果中1的个数。位运算效率很高,但是判断、计数的引入严重影响常数。
那就枚举相差的位置,题目中说明这些数都是18位二进制数以内,因此枚举量实际上是n*(1+..+18+18)。
注意使用Xor的特性,即反转特定二进制位。
注意本题要求统计每个数后面的情况,因此需要判断后一个数是否大于这个数。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int M = 18; 4 set<int> s; 5 6 int main(){ 7 int t; 8 while(scanf("%d", &t) == 1 && t != -1) s.insert(t); 9 10 for(set<int>::iterator it = s.begin(); it != s.end(); it++){ 11 int ans = 0, cur = *it; 12 for(int i = 0; i < M; i++){ 13 // reverse i-th bit 14 int t = cur ^ (1 << i); 15 if(t > cur && s.count(t)) ans++; 16 for(int j = 0; j < i; j++){ 17 int k = t ^ (1 << j); 18 if(k > cur && s.count(k)) ans++; 19 } 20 } 21 printf("%d:%d\n", cur, ans); 22 } 23 return 0; 24 }
Problem I Word Clouds Revisited
给出若干个小长方形放进一个大长方形容器中,约定如下放的方法:
1. 长方形之间按行放置,每行的长方形总宽度不能超过容器的宽度,行高按这行长方形中高度最大的计算。
2. 每个长方形必须放在前一个后面(同一行)或者另起新行。
基于此使用动态规划,记F[i]表示前i个长方形放进容器后的累计最大行高,则有(在能放下的情况下),
F[i] = max(放在上一行结尾,拉上一行若干个长方形到下一行组成新行,自己组成新行)
其中,放在上一行结尾等价于拉上一行所有长方形到下一行(主要为了代码简便)。
于是状态转移方程这样写
F[i] = max( F[i-1] + h[i] , F[j-1] + max(h[j]) ) , j 属于上一行
由于要求长方形按顺序放置,故j要逆序枚举,枚举范围是j加到i的宽度小于等于容器宽度。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 5000+10; 4 int n, c; 5 int w[maxn], h[maxn]; 6 int dp[maxn]; 7 // dp[i] = max(dp[i-1]+h[i](when >), dp[j]+max(h[j+1],,h[i])(when <)) 8 9 int main(){ 10 scanf("%d%d", &n, &c); 11 for(int i = 1; i <= n; i++) 12 scanf("%d%d", w+i, h+i); 13 memset(dp, 0, sizeof(dp)); 14 dp[0] = 0; 15 dp[1] = h[1]; 16 for(int i = 2; i <= n; i++){ 17 dp[i] = dp[i-1] + h[i]; // place on next line 18 // other situations 19 int curw = w[i], curh = h[i]; 20 for(int j = i-1; j > 0; j--){ 21 // printf("in %d %d", i, j); 22 curw += w[j]; 23 if(curw > c) break; 24 curh = max(curh, h[j]); 25 // printf(" was %d %d ", dp[i], dp[j-1] + curh); 26 dp[i] = min(dp[i], dp[j-1] + curh); 27 // printf("in%d %d\n", i, dp[i]); 28 } 29 } 30 printf("%d", dp[n]); 31 return 0; 32 }