2018年青岛站
题目链接:http://acm.zju.edu.cn/onlinejudge/showContestProblems.do?contestId=381
C题:
题意:
有长度为n的两个串s和t,你可以翻转两次子串(1->0,0->1),问有多种方案能使得s和t相等。
思路:
1.对于初始时s==t有任取一个区间,将其翻转两次即可,此时方案数为n + n * (n - 1) / 2 = n * (n + 1) / 2;
2.对于s和t有一个区间不同时,设这个区间为tt,则此时只需寻找一个大串ss包含tt,将ss串翻转一次,再将ss-tt翻转(顺序颠倒为另一方案)即可,设tt前面还有k1个字符,后面还有k2个字符,则此时方案数为(|tt| - 1)* 2 + 2 * k1 + 2 * k2;
3.对于s和t有两个区间不同时,此时方案数固定为6:
a.将第一个串翻转,第二个串翻转,顺序颠倒为另一种方案;
b.第一个串及第一二个串中间的那段一起翻转,第二个串及第一二个串中间的那段一起翻转,顺序颠倒为另一种方案;
c.第一个串及第一二个串中间那段以及第二个串进行翻转,将中间那段翻转,顺序颠倒为另一种方案。
4.对于s和t不同的区间数大于2的,此时方案数为0。
代码实现如下:
1 #include <set> 2 #include <map> 3 #include <queue> 4 #include <stack> 5 #include <cmath> 6 #include <ctime> 7 #include <bitset> 8 #include <cstdio> 9 #include <string> 10 #include <vector> 11 #include <cstdlib> 12 #include <cstring> 13 #include <iostream> 14 #include <algorithm> 15 using namespace std; 16 17 typedef long long LL; 18 typedef pair<LL, LL> pLL; 19 typedef pair<LL, int> pli; 20 typedef pair<int, LL> pil;; 21 typedef pair<int, int> pii; 22 typedef unsigned long long uLL; 23 24 #define lson rt<<1 25 #define rson rt<<1|1 26 #define lowbit(x) x&(-x) 27 #define name2str(name) (#name) 28 #define bug printf("*********\n") 29 #define debug(x) cout<<#x"=["<<x<<"]" <<endl 30 #define FIN freopen("D://code//in.txt", "r", stdin) 31 #define IO ios::sync_with_stdio(false),cin.tie(0) 32 33 const double eps = 1e-8; 34 const int mod = 1000000007; 35 const int maxn = 1e6 + 7; 36 const double pi = acos(-1); 37 const int inf = 0x3f3f3f3f; 38 const LL INF = 0x3f3f3f3f3f3f3f3fLL; 39 40 int T, n; 41 char s[maxn], t[maxn]; 42 pLL st[maxn]; 43 44 int main() { 45 #ifndef ONLINE_JUDGE 46 FIN; 47 #endif 48 scanf("%d", &T); 49 while(T--) { 50 scanf("%d", &n); 51 scanf("%s%s", s + 1, t + 1); 52 int cnt = 0, flag = 0; 53 for(int i = 1; i <= n; i++) { 54 if(s[i] != t[i] && !flag) { 55 st[cnt].first = i; 56 flag = 1; 57 } else if(s[i] == t[i] && flag) { 58 st[cnt++].second = i; 59 flag = 0; 60 } 61 } 62 if(flag) st[cnt++].second = n; 63 if(cnt == 0) printf("%lld\n", 1LL * n * (n + 1) / 2); 64 else if(cnt == 1) { 65 printf("%lld\n", 2 * (st[0].second - st[0].first) + 2 * (st[0].first - 1) + 2 * (n - st[0].second)); 66 } else if(cnt == 2) { 67 printf("6\n"); 68 } else { 69 printf("0\n"); 70 } 71 } 72 return 0; 73 }
E题:
题意:
题目背景为植物大战僵尸。
你拥有n棵植物,每棵植物坐标为i(i=0,1,2……)的初始防御值均为0,成长值为ai。
坐标0出有一辆浇水的车,该车只允许向左向右移动一格,移动到某个坐标i时就会对i上的植物进行浇水,使其防御值增长ai。
花园的防御值的定义为所有植物的防御值的最小值。
问花园的防御值的最大值为多少。
思路:
一眼二分,二分花园的防御值为x,则该题等价于固定x,求使得所有植物的防御值di大于等于x的浇水车的最小移动步数。
易知只有当这辆车在相邻两棵植物(x,x+1)间反复移动直至左边那颗植物的防御值大于等于x才转移到x+1与x+2间反复移动时浇水车的移动步数最优。
不过对于最右端的n-1和n要特别分析,最后车子可以停留在n-1而不停留在n处。
代码实现如下:
1 #include <set> 2 #include <map> 3 #include <queue> 4 #include <stack> 5 #include <cmath> 6 #include <ctime> 7 #include <bitset> 8 #include <cstdio> 9 #include <string> 10 #include <vector> 11 #include <cstdlib> 12 #include <cstring> 13 #include <iostream> 14 #include <algorithm> 15 using namespace std; 16 17 typedef long long LL; 18 typedef pair<LL, LL> pLL; 19 typedef pair<LL, int> pli; 20 typedef pair<int, LL> pil;; 21 typedef pair<int, int> pii; 22 typedef unsigned long long uLL; 23 24 #define lson rt<<1 25 #define rson rt<<1|1 26 #define lowbit(x) x&(-x) 27 #define name2str(name) (#name) 28 #define bug printf("*********\n") 29 #define debug(x) cout<<#x"=["<<x<<"]" <<endl 30 #define FIN freopen("D://code//in.txt", "r", stdin) 31 #define IO ios::sync_with_stdio(false),cin.tie(0) 32 33 const double eps = 1e-8; 34 const int mod = 1000000007; 35 const int maxn = 1e5 + 7; 36 const double pi = acos(-1); 37 const int inf = 0x3f3f3f3f; 38 const LL INF = 0x3f3f3f3f3f3f3f3fLL; 39 40 int t, n; 41 LL m; 42 int a[maxn]; 43 LL num[maxn]; 44 45 bool check(LL x) { 46 for(int i = 1; i <= n; i++) { 47 num[i] = (x + a[i] - 1) / a[i]; 48 } 49 LL cnt = 0; 50 for(int i = 1; i < n - 1; i++) { 51 cnt ++; 52 num[i]--; 53 if(cnt > m) return false; 54 if(num[i] > 0) { 55 cnt += 2 * num[i]; 56 if(cnt > m) return false; 57 if(num[i+1] > 0) { 58 num[i+1] -= num[i]; 59 } 60 num[i] = 0; 61 } 62 } 63 num[n-1]--; 64 cnt++; 65 if(num[n-1] > 0) { 66 cnt += 2 * num[n-1]; 67 if(cnt > m) return false; 68 num[n] -= num[n-1]; 69 } 70 if(num[n] > 0) { 71 num[n]--; 72 cnt++; 73 cnt += 2 * num[n]; 74 } 75 return cnt <= m; 76 } 77 78 int main() { 79 #ifndef ONLINE_JUDGE 80 FIN; 81 #endif 82 scanf("%d", &t); 83 while(t--) { 84 scanf("%d%lld", &n, &m); 85 for(int i = 1; i <= n; i++) { 86 scanf("%d", &a[i]); 87 } 88 if(m < n) { 89 printf("0\n"); 90 continue; 91 } 92 LL ub = INF, lb = 0, mid, ans; 93 while(ub >= lb) { 94 mid = (ub + lb) >> 1; 95 if(check(mid)) { 96 ans = mid; 97 lb = mid + 1; 98 } else { 99 ub = mid - 1; 100 } 101 } 102 printf("%lld\n", ans); 103 } 104 return 0; 105 }
J题:
题意:
初始时主人公带着x元钱去书店买m本书,他的买书规则如下:
1.书按照1至n排成一排进行编号;
2.如果主人公身上目前拥有的钱大于等于书的价格则一定会买这本书,且主人公拥有的钱减少书的价格;
3.如果主人公的钱少于书的价格则跳过该书。
求主人公初始拥有的钱x的最大值(如果无法估计则输出Richhman,如果不能恰好购买m本书则输出Impossible)。
思路:
对于本题由于买书规则的特殊,我们可以分析当n==m时此时主人公初始的钱是无法估计的,当书的价格为0的书的数量大于m时时Impossible。
对于其他情况则需记录书的价格为0的书的数量,记为num,最后一本价格为0的书的位置为pos。
1.如果pos<=m,则直接x=前m本书的价格+min(后面n-m本书的价格)- 1;
2.如果pos>m,则购买m-num本非0的书,然后+min(其他非0书的价格) - 1。
代码实现如下:
1 #include <set> 2 #include <map> 3 #include <queue> 4 #include <stack> 5 #include <cmath> 6 #include <ctime> 7 #include <bitset> 8 #include <cstdio> 9 #include <string> 10 #include <vector> 11 #include <cstdlib> 12 #include <cstring> 13 #include <iostream> 14 #include <algorithm> 15 using namespace std; 16 17 typedef long long LL; 18 typedef pair<LL, LL> pLL; 19 typedef pair<LL, int> pli; 20 typedef pair<int, LL> pil;; 21 typedef pair<int, int> pii; 22 typedef unsigned long long uLL; 23 24 #define lson rt<<1 25 #define rson rt<<1|1 26 #define lowbit(x) x&(-x) 27 #define name2str(name) (#name) 28 #define bug printf("*********\n") 29 #define debug(x) cout<<#x"=["<<x<<"]" <<endl 30 #define FIN freopen("D://code//in.txt", "r", stdin) 31 #define IO ios::sync_with_stdio(false),cin.tie(0) 32 33 const double eps = 1e-8; 34 const int mod = 1000000007; 35 const int maxn = 1e5 + 7; 36 const double pi = acos(-1); 37 const int inf = 0x3f3f3f3f; 38 const LL INF = 0x3f3f3f3f3f3f3f3fLL; 39 40 int t, n, m; 41 int a[maxn]; 42 43 int main() { 44 #ifndef ONLINE_JUDGE 45 FIN; 46 #endif 47 scanf("%d", &t); 48 while(t--) { 49 scanf("%d%d", &n, &m); 50 int num = 0, pos = -1; 51 LL ans = 0; 52 int mx = inf, mx2 = inf; 53 for(int i = 0; i < n; i++) { 54 scanf("%d", &a[i]); 55 mx = min(mx, a[i]); 56 if(!a[i]) { 57 num++; 58 pos = i; 59 } 60 if(i < m) ans += a[i]; 61 else { 62 mx2 = min(mx2, a[i]); 63 } 64 } 65 if(n == m) { 66 printf("Richman\n"); 67 } else { 68 if(num > m) { 69 printf("Impossible\n"); 70 } else { 71 if(m == 0) { 72 printf("%d\n", mx - 1); 73 } else { 74 if(pos >= m) { 75 m -= num; 76 int tmp = 0; 77 mx2 = inf, ans = 0; 78 for(int i = 0; i < n; i++) { 79 if(a[i] && tmp < m) { 80 ans += a[i]; 81 tmp++; 82 } else if(a[i]) { 83 mx2 = min(mx2, a[i]); 84 } 85 } 86 } 87 printf("%lld\n", ans + mx2 - 1); 88 } 89 } 90 } 91 } 92 return 0; 93 }
M题:
题意:
给你每个数对应的权值。
定义f(x)=x的每一位上的数字对应的权值之和。
定义g[0][x]=x,g[k][x]=f(g[k-1][x]),k>=1。
求g[k][x]。
思路:
经冷静分析我们可以发现当k大于等于2(打表可以发现,不过由于我只打了前几千的值,可能这个数应该要大于2,但是绝对非常小)时其实就是0和1的循环,因此我们对于前面的值进行暴力,出现0时就直接break掉,并记录此时对应的是第多少位上(记为pos),如果k<=pos,那么就直接输出,否则如果k%2==pos%2,则输出0,否则输出1。
代码实现如下:
1 #include <set> 2 #include <map> 3 #include <queue> 4 #include <stack> 5 #include <cmath> 6 #include <ctime> 7 #include <bitset> 8 #include <cstdio> 9 #include <string> 10 #include <vector> 11 #include <cstdlib> 12 #include <cstring> 13 #include <iostream> 14 #include <algorithm> 15 using namespace std; 16 17 typedef long long LL; 18 typedef pair<LL, LL> pLL; 19 typedef pair<LL, int> pli; 20 typedef pair<int, LL> pil;; 21 typedef pair<int, int> pii; 22 typedef unsigned long long uLL; 23 24 #define lson rt<<1 25 #define rson rt<<1|1 26 #define lowbit(x) x&(-x) 27 #define name2str(name) (#name) 28 #define bug printf("*********\n") 29 #define debug(x) cout<<#x"=["<<x<<"]" <<endl 30 #define FIN freopen("D://code//in.txt", "r", stdin) 31 #define IO ios::sync_with_stdio(false),cin.tie(0) 32 33 const double eps = 1e-8; 34 const int mod = 1000000007; 35 const int maxn = 30000000 + 7; 36 const double pi = acos(-1); 37 const int inf = 0x3f3f3f3f; 38 const LL INF = 0x3f3f3f3f3f3f3f3fLL; 39 40 int t, x, k; 41 int a[20], num[] = {1, 0, 0, 0, 1, 0, 1, 0, 2, 1}; 42 43 int main() { 44 scanf("%d", &t); 45 while(t--) { 46 scanf("%d%d", &x, &k); 47 if(k == 0) { 48 printf("%d\n", x); 49 continue; 50 } 51 int pos = -1, cnt = 0; 52 if(x == 0) a[cnt++] = 0; 53 while(x) { 54 a[cnt++] = x % 10; 55 x /= 10; 56 } 57 for(int i = 1; i <= k; i++) { 58 x = 0; 59 for(int i = 0; i < cnt; i++) { 60 x += num[a[i]]; 61 } 62 //debug(x); 63 if(x == 0) { 64 pos = i; 65 break; 66 } else if(i == k) { 67 printf("%d\n", x); 68 } 69 cnt = 0; 70 while(x) { 71 a[cnt++] = x % 10; 72 x /= 10; 73 } 74 } 75 //debug(pos); 76 if(pos != -1) { 77 if(k % 2 == pos % 2) { 78 printf("0\n"); 79 } else { 80 printf("1\n"); 81 } 82 } 83 } 84 return 0; 85 }