920
又到了水题时间, 这次题目更水, AK的一大堆, 作为小菜鸡的我得了210分。。
我A掉的一道题, 时间复杂度为$O(n)$, 而n的范围 < 1000, 所以说太水了。 我们能够想到, 偷相同的钱所剩下的情况相同, 且偷钱时第一个口袋的钱一定会减少, 所以我们枚举第一个口袋所剩下的钱, 通过for循环来枚举出剩下的钱数, 求出总和记做sum2, 将原序列的sum1-sum2与ans进行比较, 取max就是最终的答案, 时间大概是$O(n * a[1])$, 大概是1e7, 已经能够过去了。 不过我又想到了一个$O(n)$的算法, 假设我们第一个口袋偷了x的钱, 由于和不变, 那么第二个口袋就加上x的钱, 第三的口袋就减去x的钱…不难看出, 当n为偶数时, 小偷是偷不了钱的, 当n为奇数时, 将标号为奇数的口袋的钱的数量取min, 最后减1输出即可
#include <bits/stdc++.h> using namespace std; //typedef long long ll; const int INF = 0x3f3f3f3f; //const int MAXN = 5e5 + 100; //const int MAXM = 3e3 + 10; //const double eps = 1e-5; template < typename T > inline void read(T &x) { x = 0; T ff = 1, ch = getchar(); while(!isdigit(ch)) { if(ch == '-') ff = -1; ch = getchar(); } while(isdigit(ch)) { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } x *= ff; } template < typename T > inline void write(T x) { if(x == 0) { putchar('0'); return ; } if(x < 0) putchar('-'), x = -x; static T tot = 0, ch[20]; while(x) { ch[++tot] = x % 10 + '0'; x /= 10; } while(tot) putchar(ch[tot--]); } int n, x, ans = INF; int main() { freopen("thief.in", "r", stdin); freopen("thief.out", "w", stdout); read(n); for(int i = 1; i <= n; ++i) { read(x); if(i & 1) ans = min(ans, x); } --ans; if((n & 1) == 0) ans = 0; write(ans); return 0; }
正解
做这道题时, 优秀的搜到了80分, 由于该数列严格单调递增, 且都为正整数, 所以最小的情况就是1, 2…,n, 我们枚举每一个i, 当a[i] > a[i – 1]时, 我们有两种选择, 一种是直接跳过这个点, 继续向下搜, 还有就是将a[i]赋成a[i – 1] + 1, 继续向下, 当a[i] $\le$ a[i – 1]时, 将a[i]赋成a[i – 1] + 1, 继续向下, 时间复杂度介于$O(n)$到$O(2 ^ n)$之间, 不过还是比较优秀的。 正解的话, 我们不妨设b[i] = a[i] – i;当b数组不下降时, a数组就是递增的, 所以我们只要求出b数组的单调不下降子序列len, n – len输出即可, 特别的,当b[i] < 0时, 改点一定会修改, 找子序列时跳过即可。
#include <bits/stdc++.h> using namespace std; //typedef long long ll; const int INF = 0x3f3f3f3f; const int MAXN = 5e4 + 100; //const int MAXM = 3e3 + 10; //const double eps = 1e-5; template < typename T > inline void read(T &x) { x = 0; T ff = 1, ch = getchar(); while(!isdigit(ch)) { if(ch == '-') ff = -1; ch = getchar(); } while(isdigit(ch)) { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } x *= ff; } template < typename T > inline void write(T x) { if(x == 0) { putchar('0'); return ; } if(x < 0) putchar('-'), x = -x; static T tot = 0, ch[20]; while(x) { ch[++tot] = x % 10 + '0'; x /= 10; } while(tot) putchar(ch[tot--]); } int T, n, ans, a[MAXN], f[MAXN]; int flag = false; inline void dfs(int x, int val) { if(val >= ans) return ; if(x == n + 1) { ans = min(ans, val); return ; } if(a[x] > a[x - 1]) { dfs(x + 1, val); if(a[x] - a[x - 1] > 1) { int u = a[x]; a[x] = a[x - 1] + 1; dfs(x + 1, val + 1); a[x] = u; } } else { int u = a[x]; a[x] = a[x - 1] + 1; dfs(x + 1, val + 1); a[x] = u; } return ; } int main() { freopen("noname.in", "r", stdin); freopen("noname.out", "w", stdout); read(T); while(T--) { read(n); flag = false; ans = INF; for(register int i = 1; i <= n; ++i) { read(a[i]); if(a[i] <= a[i - 1]) flag = true; } if(!flag) { puts("0"); continue; } dfs(1, 0); write(ans); puts(""); } return 0; }
搜索
#include <bits/stdc++.h> using namespace std; //typedef long long ll; const int INF = 0x3f3f3f3f; const int MAXN = 5e4 + 100; //const int MAXM = 3e3 + 10; //const double eps = 1e-5; template < typename T > inline void read(T &x) { x = 0; T ff = 1, ch = getchar(); while(!isdigit(ch)) { if(ch == '-') ff = -1; ch = getchar(); } while(isdigit(ch)) { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } x *= ff; } template < typename T > inline void write(T x) { if(x == 0) { putchar('0'); return ; } if(x < 0) putchar('-'), x = -x; static T tot = 0, ch[20]; while(x) { ch[++tot] = x % 10 + '0'; x /= 10; } while(tot) putchar(ch[tot--]); } int T, n, ans, len, a[MAXN], b[MAXN], f[MAXN]; int main() { freopen("noname.in", "r", stdin); freopen("noname.out", "w", stdout); read(T); while(T--) { read(n); for(register int i = 1; i <= n; ++i) { read(a[i]); b[i] = a[i] - i; } memset(f, 0, sizeof(f)); ans = 1; f[1] = b[1]; for(register int i = 2; i <= n; ++i) { if(b[i] < 0) continue; if(b[i] >= f[ans]) f[++ans] = b[i]; else f[upper_bound(f + 1, f + ans + 1, b[i]) - f] = b[i]; } write(n - ans); puts(""); } return 0; }
正解
emmmmm, 还是搜索吧, 枚举每个点由哪个员工去, 将答案去min, 时间复杂度为$O(3^n)$, 过掉了30分。 正解其实很好想, 是dp, 先Floyd求最短路, 设f[i][j][k]为完成前i个任务其余俩个人在j和k的最小花费, 则显然有
f[i][j][k] = min(f[i][j][k], f[i - 1][j][k] + a[b[i - 1]][b[i]]); f[i][b[i - 1]][k] = min(f[i][b[i - 1]][k], f[i - 1][j][k] + a[j][b[i]]); f[i][b[i - 1]][j] = min(f[i][b[i - 1]][j], f[i - 1][j][k] + a[k][b[i]]);
我们可以设f[0][1][2] = f[0][2][1] = 0其余为INF, 目标状态是f[l][?][?]的最小值, $O(l * n ^ 2)$转移并取min就好了。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int INF = 0x3f3f3f3f; const int MAXN = 5e2 + 100; const int MAXM = 2e2 + 10; const double eps = 1e-5; template < typename T > inline void read(T &x) { x = 0; T ff = 1, ch = getchar(); while(!isdigit(ch)) { if(ch == '-') ff = -1; ch = getchar(); } while(isdigit(ch)) { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } x *= ff; } template < typename T > inline void write(T x) { if(x == 0) { putchar('0'); return ; } if(x < 0) putchar('-'), x = -x; static T tot = 0, ch[20]; while(x) { ch[++tot] = x % 10 + '0'; x /= 10; } while(tot) putchar(ch[tot--]); } int T, n, l, ans, b[MAXN]; int a[MAXM][MAXM], f[MAXN][MAXM][MAXM]; inline void Floyd() { for(register int k = 1; k <= n; ++k) for(register int i = 1; i <= n; ++i) for(register int j = 1; j <= n; ++j) a[i][j] = min(a[i][j], a[i][k] + a[k][j]); } int main() { freopen("service.in", "r", stdin); freopen("service.out", "w", stdout); read(T); while(T--) { read(n); read(l); for(register int i = 1; i <= n; ++i) { for(register int j = 1; j <= n; ++j) { read(a[i][j]); } } for(register int i = 1; i <= l; ++i) { read(b[i]); } Floyd(); memset(f, 0x3f, sizeof(f)); f[0][1][2] = 0; f[0][2][1] = 0; b[0] = 3; for(int i = 1; i <= l; ++i) { for(int j = 1; j <= n; ++j) { for(int k = 1; k <= n; ++k) { int s = b[i - 1], t = b[i]; f[i][j][k] = min(f[i][j][k], f[i - 1][j][k] + a[s][t]); f[i][s][k] = min(f[i][s][k], f[i - 1][j][k] + a[j][t]); f[i][s][j] = min(f[i][s][j], f[i - 1][j][k] + a[k][t]); } } } ans = INF; for(int i = 1; i <= n; ++i) { for(int j = 1; j <= n; ++j) { ans = min(ans, f[l][i][j]); } } write(ans); puts(""); } return 0; }
正解