A. Combination Lock
题意:有一个数字锁,共有n圈。给出初始状态和密码,求最小需要转动多少次。
思路:对于每一圈,选取min(dis,10-dis)
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 using namespace std; 5 char s1[1010], s2[1010]; 6 int main() 7 { 8 int n; 9 scanf("%d", &n); 10 scanf("%s%s", s1, s2); 11 int ans = 0; 12 for (int i = 0; i < n; i++) 13 { 14 int n1 = s1[i] - '0'; 15 int n2 = s2[i] - '0'; 16 int dis = abs(n1 - n2); 17 ans += min(dis, 10 - dis); 18 } 19 printf("%d ", ans); 20 return 0; 21 }
B. School Marks
题意:Vova 需要做n个测试,每个测试得分可以从1至p.现在他已经做了k张测试,他想要所有测试成绩之和不超过x,同时测试成绩的中位数不低于y.若有该方案,输出剩余测试应当得分为多少。
思路:如果当前已有分数和+n-k>x或者已有分数小于y的个数>n/2或者在满足y(比y小的补1,其余补y)时不满足x时,则无解。
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int nm[1010]; 5 int main() 6 { 7 int n, k, p, x, y; 8 scanf("%d%d%d%d%d", &n, &k, &p, &x, &y); 9 int tot = 0; 10 int nlownm = 0,lownm=0; 11 for (int i = 0; i < k; i++) 12 { 13 scanf("%d", nm + i); 14 tot += nm[i]; 15 if (nm[i] >= y) nlownm++; 16 else lownm++; 17 } 18 if (tot + n - k > x||lownm>n/2) printf("-1 "); 19 else 20 { 21 int re = n - k; 22 int rev = x - tot; 23 if (nlownm <= n / 2 + 1 && rev < (n / 2 + 1 - nlownm)*y + n / 2 - lownm) printf("-1 "); 24 else 25 { 26 while (nlownm < n / 2 + 1) 27 { 28 nm[k++] = y; 29 nlownm++; 30 } 31 while (k < n) nm[k++] = 1; 32 for (int i = re; i >=1; --i) 33 { 34 printf("%d", nm[k-i]); 35 if (i>1) printf(" "); 36 } 37 printf(" "); 38 } 39 } 40 return 0; 41 }
C. Ice Cave
题意:有个n*m的冰块,格子为‘.’表示此处冰块完整,为'X'表示冰块破碎。如果走到一处完整的冰块,其会破碎,走到破碎的冰块上,冰块会裂掉且你会掉下去。问能够从目的冰块格子落下?
思路:如果存在从起点到终点的路径,如果终点为破碎冰块或者为完整冰块且附近至少有2块完整冰块(当起点和终点为隔壁冰块时,只需要1块其他邻近完整冰块)时,则成功;否则失败。
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 using namespace std; 5 char mp[510][510]; 6 bool vis[510][510]; 7 int tag_r, tag_c; 8 int st_r, st_c; 9 int dr[] = { 0,0,1,-1 }; 10 int dc[] = { 1,-1,0,0 }; 11 int n, m; 12 bool DFS(int r, int c) 13 { 14 for (int i = 0; i < 4; i++) 15 { 16 int tr = r + dr[i], tc = c + dc[i]; 17 if (tr >= n || tr < 0 || tc >= m || tc < 0) continue; 18 if (tr == tag_r && tc == tag_c) return true; 19 else if(mp[tr][tc]=='.'&&!vis[tr][tc]) 20 { 21 vis[tr][tc] = true; 22 mp[tr][tc] = 'X'; 23 bool flag=DFS(tr, tc); 24 mp[tr][tc] = '.'; 25 if (flag) return true; 26 } 27 } 28 return false; 29 } 30 int main() 31 { 32 scanf("%d%d", &n, &m); 33 for (int i = 0; i < n; i++) scanf("%s", mp + i); 34 scanf("%d%d%d%d", &st_r, &st_c, &tag_r, &tag_c); 35 st_r--, st_c--, tag_r--, tag_c--; 36 int cnt = 0; 37 for (int i = 0; i < 4; i++) 38 { 39 int tr = tag_r + dr[i], tc = tag_c + dc[i]; 40 if (tr >= n || tr < 0 || tc >= m || tc < 0) continue; 41 if (mp[tr][tc]=='.') cnt++; 42 } 43 bool ok = DFS(st_r, st_c); 44 if (ok) 45 { 46 if (mp[tag_r][tag_c] == 'X') printf("YES "); 47 else if (cnt >= 2||((abs(tag_r - st_r) + abs(tag_c - st_c) == 1)&&cnt)) printf("YES "); 48 else printf("NO "); 49 } 50 else printf("NO "); 51 return 0; 52 }
D. Bad Luck Island
题意:石头怪、剪刀怪、布怪各有r,s,p个,每两个怪物遇到的几率相同。相遇时,石头怪会杀掉剪刀怪,剪刀怪会杀掉布怪,布怪会杀掉石头怪。经过很长一段时间后,求3中怪物最后只剩其自己一种怪物的几率各是多少?
思路:假设当前有tr个石头怪,ts个剪刀怪,tp个布怪,那么不同种类的相遇可能数有tr*ts+ts*tp+tp*tr种,对于石头怪,其遇到天敌布怪的几率为tp*tr/(tr*ts+ts*tp+tp*tr),则rate[tr-1][ts][tp]+=rate[tr][ts][tp]*tp*tr/(tr*ts+ts*tp+tp*tr).
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 double rr[110][110][110]; 5 int main() 6 { 7 int r, s, p; 8 scanf("%d%d%d", &r, &s, &p); 9 rr[r][s][p] = 1.0; 10 for (int tr = r; tr >= 0; --tr) 11 { 12 for (int ts = s; ts >= 0; --ts) 13 { 14 for (int tp = p; tp >= 0; --tp) 15 { 16 int tot = tr * ts + tr * tp + ts * tp; 17 if (tot == 0) continue; 18 if (tr) rr[tr - 1][ts][tp] += rr[tr][ts][tp] * 1.0*tr*tp / tot; 19 if (ts) rr[tr][ts - 1][tp] += rr[tr][ts][tp] * 1.0*ts*tr / tot; 20 if (tp) rr[tr][ts][tp - 1] += rr[tr][ts][tp] * 1.0*tp*ts / tot; 21 } 22 } 23 } 24 double ans_r = 0, ans_s = 0, ans_p = 0; 25 for (int i = 1; i <= r; i++) ans_r += rr[i][0][0]; 26 for (int i = 1; i <= s; i++) ans_s += rr[0][i][0]; 27 for (int i = 1; i <= p; i++) ans_p += rr[0][0][i]; 28 printf("%.12lf %.12lf %.12lf ", ans_r, ans_s, ans_p); 29 return 0; 30 }
E. Infinite Inversions
题意:在一个1,2,3,4,5,...序列中,进行n次交换,求逆序对数?
思路:因为数值很大,对所有数进行离散化;采用树状数组进行求解逆序对,按照顺序插入树状数组,更新值为1.注意,除了进行交换的数之间存在逆序数,原本不动的数和进行交换的数之间也存在逆序对。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<map> 5 #include<cmath> 6 using namespace std; 7 const int maxn = 100010; 8 const int maxv = maxn * 4; 9 int a[maxn], b[maxn],val[maxv]; 10 int sumv[maxv]; 11 int tree[maxv]; 12 int maxnum; 13 map<int, int>mp; 14 int lowbit(int x) 15 { 16 return (x&(-x)); 17 } 18 int Query(int k) 19 { 20 int res = 0; 21 while (k) 22 { 23 res += tree[k]; 24 k -= lowbit(k); 25 } 26 return res; 27 } 28 void Update(int x, int k) 29 { 30 while (x <= maxnum) 31 { 32 tree[x] += k; 33 x += lowbit(x); 34 } 35 } 36 int main() 37 { 38 int n; 39 scanf("%d", &n); 40 for (int i = 1; i <= n; i++) 41 { 42 scanf("%d%d", &a[i], &b[i]); 43 val[++maxnum] = a[i]; 44 val[++maxnum] = b[i]; 45 } 46 sort(val + 1, val + 1 + maxnum); 47 maxnum = unique(val + 1, val + 1 + maxnum) - val-1; 48 for (int i = 1; i <= maxnum;i++) sumv[i] = sumv[i - 1] + val[i] - val[i - 1] - 1;//统计val[i]前没有被交换的元素个数 49 for (int i = 1; i <= maxnum; i++) mp[val[i]] = i;//对离散结果编号 50 //对离散化结果进行交换 51 for (int i = 1; i <= n; i++) 52 { 53 int index1 = mp[a[i]], index2 = mp[b[i]]; 54 swap(val[index1], val[index2]); 55 } 56 long long ans = 0; 57 for (int i = 1; i <= maxnum; i++) 58 { 59 int index = mp[val[i]]; 60 Update(index, 1); 61 ans += Query(maxnum) - Query(index);//找到(index,maxnum]中元素个数,说明在之前已经插入,构成逆序对 62 ans += abs(sumv[index] - sumv[i]);//如果该数最后仍在原位,值为0;如果后移,则原位与当前之间的数都比该数大;否则,当前的数和原位之间的数都比该数小 63 } 64 printf("%lld ", ans); 65 return 0; 66 }