T1
80分算法
写了一个最水的贪心(毫无正确性),每次取最大得数给 Bob,取完后其他的给 Alice,用 max_element 很短就能实现…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
   | #include <bits/stdc++.h> using namespace std; char num[40], tmp[40]; int n, tot, BobRemain, pos = 1, zeroNum; long long AliceVal, BobVal; inline int getMaxPos(const char* num) {     return max_element(num + pos, num + tot - BobRemain + 2) - num; } inline long long solve() {     memcpy(tmp, num, sizeof(num));     for (register int i = 1; i <= n; i++) {         pos = getMaxPos(tmp);         BobVal = BobVal * 10 + tmp[pos] - '0';         tmp[pos] = -1;         BobRemain--;     }     for (register int i = 1; i <= tot; i++) {         if (tmp[i] != -1) {             AliceVal = AliceVal * 10 + tmp[i] - '0';         }     }     BobRemain = n;     return AliceVal + BobVal; } int main() {     freopen("hello.in", "r", stdin);     freopen("hello.out", "w", stdout);     cin >> n >> num + 1;     tot = n << 1, BobRemain = n;     cout << solve();     return 0; }
   | 
 
100分算法
此题应该 dp,状态转移方程为
$$f[i][j] = \max(f[i - 1][j] + num[i + j] \times 10^{n-i}, f[i][j - 1] + num[i + j] \times 10^{n-j})$$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
   | #include <bits/stdc++.h> using namespace std; int n; long long f[21][21]; char s[40]; int num[40]; int main() {     cin >> n >> s + 1;     for (register int i = 1; i <= (n << 1); i++)         num[i] = s[i] ^ '0';     for (register int i = 1; i <= n; i++)         f[i][0] = f[0][i] = f[i - 1][0] + num[i] * (long long)pow(10, n - i);     for (register int i  = 1; i <= n; i++)         for (register int j = 1; j <= n; j++)             f[i][j] = max(f[i - 1][j] + num[i + j] * (long long)pow(10, n - i), f[i][j - 1] + num[i + j] * (long long)pow(10, n - j));     cout << f[n][n];     return 0; }
   | 
 
T2
玄学骗分 by hyj
hyj 表示此题可以骗分,10 行的玄学方法即可骗到 40 分…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
   | #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int main() {     freopen("rect.in", "r", stdin);     freopen("rect.out", "w", stdout);     int a;     string s;     ios::sync_with_stdio(0);     cin.tie(0);     cin >> a;     cin >> s;     int num[4001], n = s.length();     for (register int i = 1; i <= n; ++i)         num[i] = s[i - 1] - '0';     int ans = 1;     for (register int i = 1; i <= n; ++i) {         ans *= num[i];     }     ans = (ans / a) / 2;     cout << ans;     return 0; }
   | 
 
100分
由于此题的矩阵由 $s[i] \times s[j]$ 构成的,故 $a$ 为 $sum[x_1..x_2]$ 的倍数,故可以先把满足条件的 $sum$ 全部放进一个 HashMap 里,对应的值为方案数,如果 $a$ 不为 $0$,则遍历 HashMap 乘上对应方案数,再累加即可。当 $a$ 为 $0$ 时,$sum[y]$ 是可以随便取的,$ans = h[0] \times (len \times (len + 1) - h[0])$。
注意对0的特殊判断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
   | #include <bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/hash_policy.hpp> using namespace std; using namespace __gnu_pbds; typedef cc_hash_table<int, int> HashMap; int a, len; char str[10001]; long long ans; HashMap h; int main() {     ios::sync_with_stdio(false);     cin.tie(0);     cin >> a >> str + 1;     len = strlen(str + 1);     for (register int i = 1; i <= len; i++) {         register int cnt = 0;         for (register int j = i; j <= len; j++) {             cnt += str[j] ^ '0';             if (!cnt || !(a % cnt))                 h[cnt]++;         }     }     if (a) {         for (HashMap::iterator it = h.begin(); it != h.end(); it++)             if (it->first && h.find(a / it->first) != h.end())                 ans += (long long)it->second * h[a / it->first];     } else {         ans = (long long)h[0] * (len * (len + 1) - h[0]);     }     cout << ans;     return 0; }
   | 
 
T3
此题暴力求最短路可以得 30 分,正解应逆向思考,把一个个删点看成一个个加点,相当于每次往闭包里加一个点,然后不断更新这样就可以的到复杂度为 $O(n ^ 3)$ 的算法,但需要注意一下常数…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
   | #include <bits/stdc++.h> using namespace std; #define inline __attribute__((optimize("O3"))) inline const int iol = 1024 * 1024; char buf[iol], *s, *t, ioc; bool iosig; inline char read() {     if (s == t) {         t = (s = buf) + fread(buf, 1, iol, stdin);         if (s == t) return -1;     }     return *s++; } template<class T> inline bool read(T& x) {     iosig = false;     for (ioc = read(); !isdigit(ioc); ioc = read()) {         if (ioc == -1) return false;         if (ioc == '-') iosig = true;     }     x = 0;     while (ioc == '0') ioc = read();     for (; isdigit(ioc); ioc = read())         x = (x << 1) + (x << 3) + (ioc ^ '0');     s--;     if (iosig) x = -x;     return true; } using namespace std; int n, a[501], g[501][501]; bool vis[501]; int f[501][501], ans[501]; __attribute__((optimize("O3"))) int main() {     read(n);     for (register int i = 1; i <= n; i++)         for (register int j = 1; j <= n; j++)             read(g[i][j]);     for (register int i = 1; i <= n; i++)         read(a[i]);     memset(f, 127, sizeof(f));     for (register int i = n; i >= 1; i--) {         vis[a[i]] = true;         f[a[i]][a[i]] = 0;         for (register int j = 1; j <= n; j++) {             if (vis[j]) {                 for (register int k = 1; k <= n; k++) {                     if (vis[k]) {                         f[j][a[i]] = min(f[j][a[i]], f[j][k] + g[k][a[i]]);                         f[a[i]][j] = min(f[a[i]][j], f[k][j] + g[a[i]][k]);                     }                 }             }         }         ans[i] = 0;         for (register int j = 1; j <= n; j++) {             if (vis[j]) {                 for (register int k = 1; k <= n; k++) {                     if (vis[k]) {                         f[j][k] = min(f[j][k], f[j][a[i]] + f[a[i]][k]), ans[i] += f[j][k];                     }                 }             }         }     }     for (register int i = 1; i <= n; i++)         cout << ans[i] << " ";     return 0; }
   |