这个月相比上个月好多了,也开始按照规律做题和学新东西,就是博客写少了一点。3月份应该会多写写博客。
二月算是彻底搞清了方向找回了初心,也知道要怎么走了。希望之后能一直保持一个较好的状态。
没了。
Personal Blog
这个月相比上个月好多了,也开始按照规律做题和学新东西,就是博客写少了一点。3月份应该会多写写博客。
二月算是彻底搞清了方向找回了初心,也知道要怎么走了。希望之后能一直保持一个较好的状态。
没了。
前天晚上打得一场,没想到神仙特别多,把我这个卡在 D 题的小 sb 直接区分出来了,害。
这道题看了题解之后发现就是一道 sb 题。
考虑将每一列看成一个数,发现如果忽略掉列的操作,这些数仍然满足等差的条件,所以我们只要暴力算完第一列就可以进行等差了。如果考虑列的操作,那么我们就大力暴力就行了,时间复杂度是\(O(n + m)\)。
回来了一个星期有余,一切都挺顺利的(特别是逃掉了寒假作业),只不过周末发了个烧,现在喉咙还是很痛。这些都算是小插曲,没什么大不了的。
在经历了几周的 OI 训练之后回到学校,感觉文化课在变得越来越简单了。除了毒瘤数学上的速度跟开飞机一样、这一段时间的作业有点跟不上之外,其他的科目都算是小清新,物理补完的天数已经可以预估出来了,化学再巩固巩固,必修二的时候,必修一的综合练习也做做。生物这种平常写题周末抱抱佛脚 80 就稳了的科目目前还不需要担心。语文比较毒瘤,随它去吧。
班上最近出了点事情,反正没触及到我的事情我基本上懒得理。触及到了估计也是些鸡毛蒜皮的小事情,反正他就喜欢管这种玩意,也管不好这种玩意。我就佛系的学习就行了。
其实刚开始我心态是很崩的,简章发布的那天我又是发烧,所以心情直接爆炸。这个分数不是傻逼都考得到吗?
即使明年政策会更加缩紧,我也会继续全力学。管他狼来不来,我特么就是要杀出一条血路,即使凉了我就把这套放在文化课上。我就不信一堆死老头老太太能掌握我的人生。
先这样吧,上晚自习了。
今天比赛状态极差,又困、又饿,眼睛又干。
我们先把问题转换为三角矩阵上两点的距离,可以类比曼哈顿距离,我们可以把距离分为纵向和横向两种来考虑。
首先是纵向。如果\((x_1,y_1)\)要到\((x_2,y_2)\),那么分下面几种情况:
那么再来看横向。我们发现,如果我们把上方的三角形扩大成这样:
我们发现,这一范围内的三角形不需要额外的横向贡献,只需要计算纵向贡献即为答案。对于在同一行却不在这个区域内的三角形,横向贡献也非常好计算,做差乘二即可。
记得要对输入点进行排序。
// A.cpp #include <bits/stdc++.h> #define pr pair<int, int> using namespace std; const int MAX_N = 1001000; pr prs[MAX_N]; int n, m, si, sj; int answer, exitI, exitJ; int main() { answer = 0x3f3f3f3f; scanf("%d%d%d%d", &m, &n, &si, &sj); for (int i = 1; i <= n; i++) scanf("%d%d", &prs[i].first, &prs[i].second); sort(prs + 1, prs + 1 + n); for (int i = 1; i <= n; i++) { pr pta = prs[i], ptb = make_pair(si, sj); if (pta.first < ptb.first) swap(pta, ptb); int jl = ptb.second, jr = ptb.second + (pta.first - ptb.first) * 2; int ans = (pta.first - ptb.first) << 1; if (pta.second >= jl && pta.second <= jr && (ans < answer || (ans == answer && exitJ >= prs[i].second))) { answer = ans, exitI = prs[i].first, exitJ = prs[i].second; if ((pta.second & 1) != (ptb.second & 1)) answer -= 1; continue; } ans += min(abs(pta.second - jl), abs(pta.second - jr)); if (ans < answer || (ans == answer && exitJ >= prs[i].second)) answer = ans, exitI = prs[i].first, exitJ = prs[i].second; } printf("%d %d\n%d", exitI, exitJ, answer + 1); return 0; }
首先,这道题的\(w_i\)毫无卵用。我们来看这个\(w_i\)对亏损的贡献:
\[ \sum_{i=1}^{n}( i-w_{s_i} )= \frac{n(n-1)}{2}-\sum_{i=1}^{n} w_i \]
所以顺序根本不会造成影响。所以,我们来找一条最短的一笔画路径且字典序最小,方可保证答案最简。
因为题目里明显的说了(可惜我没看到,眼瞎了)
能够离开每个村子的路口的数目一定是2,4或者8。
我可真是个傻逼。
所以,用邻接表存图,然后按标号从小到大进行 DFS 写栈,最后反向弹栈输出即可。
// B.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 220; int n, m, wi[MAX_N], tmpx, tmpy, dist[MAX_N][MAX_N], tot; stack<int> stk; void dfs(int u) { for (int i = 1; i <= n; i++) if (dist[u][i]) { dist[u][i]--, dist[i][u]--; dfs(i); } stk.push(u); } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &wi[i]); for (int i = 1; i <= m; i++) scanf("%d%d", &tmpx, &tmpy), dist[tmpx][tmpy]++, dist[tmpy][tmpx]++; dfs(1); printf("%d\n", stk.size() - 1); while (!stk.empty()) printf("%d ", stk.top()), stk.pop(); return 0; }
我们可以考虑设置状态\(f[i][j][k]\)为从节点\(i\)到\(j\)走了\(k\)条边的总长度,然后 Floyd 预处理,最后\(O(n)\)回答即可,傻逼题。
// C.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 55, MAX_M = 1200; int n, m, tmpx, tmpy, tmpz, f[MAX_N][MAX_N][MAX_M], dist[MAX_N][MAX_N], q; int main() { scanf("%d%d", &n, &m); memset(f, 0x3f, sizeof(f)), memset(dist, 0x3f, sizeof(dist)); for (int i = 1; i <= m; i++) scanf("%d%d%d", &tmpx, &tmpy, &tmpz), dist[tmpx][tmpy] = min(dist[tmpx][tmpy], tmpz); for (int i = 1; i <= n; i++) f[i][i][0] = 0; for (int s = 1; s <= n; s++) for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (f[i][j][s] > f[i][k][s - 1] + dist[k][j]) f[i][j][s] = f[i][k][s - 1] + dist[k][j]; scanf("%d", &q); while (q--) { double ans = (double)0x3f3f3f3f; int i, j; bool flag = true; scanf("%d%d", &i, &j); for (int s = 1; s <= n; s++) if (1.0 * f[i][j][s] / (1.0 * s) < ans && f[i][j][s] != (double)0x3f3f3f3f) ans = min(ans, 1.0 * f[i][j][s] / (1.0 * s)), flag = false; if (flag) puts("OMG!"); else printf("%.3lf\n", ans); } return 0; }