今天做的是第五届河南省省赛,我挫到爆了,只出了三题,都是水题,个人赛垫底。
先总结一下,今天写最水的A题居然WA了两次,关键是调了半个小时,浪费了不少时间,也影响了心情。然后做的是同样水的
F题,还好敲的比较快,也顺利一A。然后剩下三个多小时在梦游,将D题敲到了200多行,WA了2次,中途去写了G题,结果题意看错了,
WA了1次,看各位大牛已经A到了7题,又回来写D题,还是WA,最后才想到B题过的人也那么多,所以去写B题,WA了两次才A。惨不忍睹!
A:奇怪的排序
将一个数组的所有数翻转,然后从小到大排序,输出排序后的结果,例如13翻转成31,超级水的一道题,真心不应该
#include <stdio.h> #include <string.h> #include <stdlib.h> const int MAXD = 60; typedef struct Node { int x, y; }E; E e[MAXD]; int A, B; int cmp(const void *_p, const void *_q) { E *p = (E *)_p; E *q = (E *)_q; return p -> y - q -> y; } int main() { int n; scanf("%d", &n); while(n --) { scanf("%d%d", &A, &B); int k = 0; for(int i = A; i <= B; i ++) { e[k].x = i; char str[20]; int t = i, m = 0; while(t) { str[m ++] = t % 10 + '0'; t /= 10; } str[m] = '\0'; //printf("%s\n", str); int s = 1, j; e[k].y = 0; for(j = strlen(str) - 1; j >= 10; ) if(str[j] == '0') j --; for(; j >= 0 ; j --) { e[k].y += (str[j] - '0') * s; s *= 10; } //printf("%d\n", e[k].y); k ++; } qsort(e, k, sizeof e[0], cmp); k --; for(int i = 0; i < k; i ++) { printf("%d ", e[i].x); } printf("%d\n", e[k].x); } return 0; }
B: 最强DE 战斗力
将一个1000以内的数拆成N个数,N不给出,自己判断,使得这N个数的乘积最大,需要用到高精度,但是这不是关键。最后才想到拆成3 和 2是最优的,优先选3。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> using namespace std; const int base = 10000; const int width = 4; const int N = 1000; struct bint { int ln, v[N]; bint (int r = 0) { for(ln = 0; r > 0; r /= base) v[ln ++] = r % base; } bint & operator = (const bint& r) { memcpy(this, &r, (r.ln + 1) * sizeof (int)); return *this; } }; /* bool operator <(const bint& a, const bint& b) { int i; if(a.ln != b.ln) return a.ln < b.ln; for(i = a.ln - 1; i >= 0 && a.v[i] == b.v[i]; i --) { return i < 0 ? 0 : a.v[i] < b.v[i]; } } */ bint operator * (const bint& a, const bint& b) { bint res; res.ln = 0; if(0 == b.ln) {res.v[0] = 0; return res;} int i, j, cy; for(i = 0; i < a.ln; i ++) { for(j = cy = 0; j < b.ln || cy > 0; j ++, cy /= base) { if(j < b.ln) cy += a.v[i] * b.v[j]; if(i + j < res.ln) cy += res.v[i + j]; if(i + j >= res.ln) res.v[res.ln ++] = cy % base; else res.v[i + j] = cy % base; } } } bool read(bint& b, char buf[]) { //if(1 != scanf("%s", buf)) return 0; int w, u, ln = strlen(buf); memset(&b, 0, sizeof(bint)); if('0' == buf[0] && 0 == buf[1]) return 1; for(w = 1, u = 0; ln; ) { u += (buf[-- ln] - '0') * w; if(w * 10 == base) { b.v[b.ln ++] = u, u = 0, w = 1; } else w *= 10; } if(w != 1) b.v[b.ln ++] = u; return 1; } void write(const bint& v) { int i; printf("%d", v.ln == 0 ? 0 : v.v[v.ln - 1]); for(i = v.ln - 2; i >= 0; i --) printf("%04d", v.v[i]); printf("\n"); } int n, t; bint s, v, u; int main() { scanf("%d", &n); while(n --) { scanf("%d", &t); int k = t / 3; char str1[10] = "1", str2[10] = "2", str3[10] = "3"; read(s, str1); read(v, str2); read(u, str3); //write(s); //write(v); //write(u); for(int i = 0; i < k - 1; i ++) { s = s * u; } if(t % 3 == 1) { s = s * v; s = s * v; } else if(t % 3 == 2) { s = s * u; s = s * v; } else { s = s * u; } write(s); } return 0; }
C: 试 制 品
一道关于字符串的题,暂时没看。
D:遥控器
这道题是一道类似模拟调频道的题。
Dr.Kong 有一台高级电视机,这台电视机可以接受100个频道(从0到99编号)。电视的配套
遥控器有13个按钮:
1 2 3 ↑
4 5 6 ↓
7 8 9
— 0
当按"↑"键时,当前频道编号会增加1(如果当前为99频道,则会切换到0频道)。如果按"↓"
键,当前频道编号会减小1(如果当前为0频道,则会切换到99频道)。当要切换到0~9频道时,可以
直接在遥控器上按相应的键。当要切换到10~99频道时,可以先按"—"键,然后按2个与频道编号
相对应的数字键(即先按与频道编号的十位数字相对应的键,然后按与个位数字相对应的键)。
由于遥控器长时间的使用和某些未知原因,遥控器上的某些键已经坏了,不能再起作用了。
现在你的任务是,能否告诉Dr.Kong,如何用最少的按键次数来将频道从编号X切换到编号Y。
我当时是根据键来枚举,越来越乱,越写越多,最后就悲剧了。
其实应该按照步数来枚举,枚举需要按上下键的步数。如果我们只通过按上下的话,从X到Y的步数可以直接求。
从任一个可通过按数字键到的频道到Y的步数 + 数字键到该频道的步数也可以求。然后找出最小值即可。
#include <stdio.h> #include <string.h> #include <stdlib.h> int a[15]; int x, y; int cnt, ans; int id(int x) { if(x < 0) return x + 100; else return x % 100; } int min(int a, int b) { if(a == -1) return b; else return a < b ? a : b; } int to(int x) { x = id(x); if(x / 10 == 0) { return a[x]; } int tx = x / 10, bx = x % 10; if(a[10] && a[tx] && a[bx]) return 3; return 0; } int main() { //freopen("543.in", "r", stdin); //freopen("D.out", "w", stdout); int t; scanf("%d", &t); while(t --) { ans = -1; scanf("%d%d%d%d", &a[1], &a[2], &a[3], &a[11]); scanf("%d%d%d%d", &a[4], &a[5], &a[6], &a[12]); scanf("%d%d%d", &a[7], &a[8], &a[9]); scanf("%d%d", &a[10], &a[0]); scanf("%d%d", &x, &y); //枚举步数 for(int i = 0; i < 100; i ++) { if(a[11]) { if(id(y - i) == x) //向上按i次 ans = min(ans, i); else if(to(y - i)) //可以到一个频道 + 向上i次 ans = min(ans, to(y - i) + i); } if(a[12]) { if(id(y + i) == x)//向下按i次 { ans = min(ans, i); } else if(to(y + i))//到一个频道 + 向下i次 ans = min(ans, to(y + i) + i); } } printf("%d\n", ans); } return 0; }
比赛时写的挫B代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <algorithm> using namespace std; int a[15]; int x, y; int cnt, ans; int main() { int t; scanf("%d", &t); while(t --) { ans = 110; scanf("%d%d%d%d", &a[1], &a[2], &a[3], &a[11]); scanf("%d%d%d%d", &a[4], &a[5], &a[6], &a[12]); scanf("%d%d%d", &a[7], &a[8], &a[9]); scanf("%d%d", &a[10], &a[0]); scanf("%d%d", &x, &y); int cur, ty, by; bool ok = false; if(a[11]) { ok = true; if(y < x) { cnt = y + 99 - x; ans = min(cnt, ans); } else { cnt = y - x; ans = min(cnt, ans); } } if(a[12]) { ok = true; if(y < x) { cnt = x - y; ans = min(cnt, ans); } else { cnt = x + 99 - y; ans = min(cnt, ans); } } if(y < 10) { if(a[y]) { cnt = 1; if(cnt < ans) ans = cnt; ok = true; } else { cur = y; if(a[11]) { while(cur --) { if(a[cur]) { cnt = y - cur; if(cnt < ans) ans = cur; ok = true; break; } if(cur == -1) cur = 99; if(cur >= 10) { if(!a[10]) break; ty = cur / 10, by = cur % 10; if(a[ty] && a[by]) { ok = true; cnt = 3; cnt += (y + 99 - cur); if(cnt < ans) ans = cnt; } } } } cur = y; if(a[12]) { while(cur ++) { if(a[cur]) { cnt = cur - y; if(cnt < ans) ans = cur; ok = true; break; } if(cur == 100) cur = 0; if(cur >= 10) { if(!a[10]) break; ty = cur / 10, by = cur % 10; if(a[ty] && a[by]) { ok = true; cnt = 3; cnt += (cur - y); if(cnt < ans) ans = cnt; } } } } } } else { ty = y / 10, by = y % 10; if(a[ty] && a[by]) { cnt = 3; ans = min(cnt, ans); ok = true; } else { cur = y; if(a[11]) { while(cur --) { if(cur > 0) } } } } } }
E:奇妙的图案
计算几何,暂时先不搞。
F:Metric Matrice
判断一个矩阵是不是最短路径的矩阵。是的话输出”0“,否则看违反了下哪条规则就输出几,遍历五遍矩阵就可以了。
A distance matrix a[i][j] is a metric if and only if
1. a[i][i] = 0
2, a[i][j]> 0 if i != j
3. a[i][j] = a[j][i]
4. a[i][j] + a[j][k] >= a[i][k] i != j != k
#include <stdio.h> #include <string.h> #include <stdlib.h> const int MAXN = 35; int a[MAXN][MAXN]; int n; int judge() { for(int i = 0; i < n; i ++) { for(int j = 0; j < n; j ++) { if(a[i][i] != 0) return 1; } } for(int i = 0; i < n; i ++) { for(int j = 0; j < n; j ++) { if(i == j) continue; if(a[i][j] <= 0) return 2; } } for(int i = 0; i < n; i ++) { for(int j = 0; j < n; j ++) { if(a[i][j] != a[j][i]) return 3; } } for(int i = 0; i < n; i ++) { for(int j = 0; j < n; j ++) { for(int k = 0; k < n; k ++) { if(i == j || j == k || i == k) continue; if(a[i][j] + a[j][k] < a[i][k]) return 4; } } } return 0; } int main() { int t; scanf("%d", &t); while(t --) { scanf("%d", &n); for(int i = 0; i < n; i ++) for(int j = 0; j < n; j ++) scanf("%d", &a[i][j]); printf("%d\n", judge()); } return 0; }
G: Divideing Jewels
给出权值从1到10的物品的各自的数目,然后问是否能平均分给两个人,使得两个人拿到的物品的总价值相等。首先判断所有物品的总价值是不是偶数,是偶数
的话再看能不能将这些物品分配到一个人手里,使得他获得的价值是总价值的一半。可以转化成多重背包问题,知道了物品的价值和数目,我们可以将物品的体积
设成和它的价值相同,然后用一个总价值一半体积的背包来装这些物品,看最终获得的最大价值是不是等于它的体积。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <algorithm> using namespace std; const int MAXN = 100005; int a[15], f[MAXN], V; void ZeroOnePack(int F[], int C, int W) { for(int v = V; v >= C; v --) F[v] = max(F[v], F[v - C] + W); } void CompletePack(int F[], int C, int W) { for(int v = C; v <= V; v ++) F[v] = max(F[v], F[v - C] + W); } void MultiplePack(int F[], int C, int W, int M) { if(C * M >= V) { CompletePack(F, C, W); return; } int k = 1; while(k < M) { ZeroOnePack(F, k * C, k * W); M -= k; k <<= 1; } ZeroOnePack(F, C * M, W * M); } int main() { int t = 0; while(true) { int total = 0; for(int i = 1; i <= 10; i ++) { scanf("%d", &a[i]); total += a[i] * i; } if(total == 0) break; ++ t; if(total & 1) printf("#%d:Can't be divided.\n", t); else { int target = total >> 1; memset(f, 0, sizeof f); V = target; for(int i = 1; i <= 10; i ++) { MultiplePack(f, i, i, a[i]); } if(f[target] == target) { printf("#%d:Can be divided.\n", t); } else printf("#%d:Can't be divided.\n", t); printf("\n"); } } return 0; }
H: Interesting Punch-Bowl
神题,貌似当时他们省赛没人过,但是被斌牛搞定了。