[关闭]
@dxbdly 2020-12-27T04:00:04.000000Z 字数 4342 阅读 193

C2020 2020.12.26模拟赛

信息学——模拟赛


考试情况

期望得分:

T1 T2 T3 总分
100 100 0 200

实际得分:

T1 T2 T3 总分
100 5 0 105

T1 Prob1

分析

看着感觉像个树型DP,后来发现贪心算一遍就好了。

对于当前节点(当前节点只有1个病毒),计算他有多少个儿子,然后做倍增操作,直到病毒树大于儿子数。

然后给每个儿子送一个病毒,递归操作即可。

正确性:

  1. //The code is from dawn_sdy
  2. #include<bits/stdc++.h>
  3. using namespace std;
  4. inline int read() {
  5. int x = 0;
  6. char c = getchar();
  7. bool f = 0;
  8. while(!isdigit(c)) f |= (c == '-'), c = getchar();
  9. while(isdigit(c)) x = (x * 10) + (c ^ 48), c = getchar();
  10. return f ? -x : x;
  11. }
  12. const int maxn = 1e5 + 5;
  13. int n;
  14. struct node {
  15. int v, nex;
  16. }edge[maxn << 1];
  17. int head[maxn], len, ans;
  18. inline void make_map(int u, int v) {
  19. len++; edge[len].nex = head[u]; edge[len].v = v; head[u] = len;
  20. }
  21. inline void Search(int x, int fa) {
  22. int sum = 0, cnt = 1;
  23. for(register int i = head[x]; i; i = edge[i].nex) {
  24. int y = edge[i].v;
  25. if(y == fa) continue;
  26. sum++;
  27. }
  28. while(cnt <= sum) cnt <<= 1, ans++;
  29. for(register int i = head[x]; i; i = edge[i].nex) {
  30. int y = edge[i].v;
  31. if(y == fa) continue;
  32. ans++, Search(y, x);
  33. }
  34. }
  35. int main() {
  36. // freopen("prob1.in", "r", stdin);
  37. // freopen("prob1.out", "w", stdout);
  38. n = read();
  39. for(register int i = 1; i < n; ++i) {
  40. int u = read(), v = read(); make_map(u, v), make_map(v, u);
  41. }
  42. Search(1, 0); printf("%d", ans);
  43. return 0;
  44. }

T2 Prob2

分析

考场上想的算法其实是对的,打shi了。

显然,为了方便,我们让矩阵的端点由已知点确定(换句话说就是左下端点,右上端点一定是已知点)

这个时候子集的数量就是矩阵的数量,所以我们只要考虑能构造出多少矩阵就好了。

先将所有点按 为第一关键字, 为第二关键字排序。

那么,我们可以枚举出矩阵限制 坐标的两点,记为 ,然后以端点为这两点的矩形往左右拓展。(类似于扫描线)

设在 之上的点有 个,在 之下的点有 个( 之上)

则贡献为

考虑 如何求出,考场上写的是树状数组,后来发现一遍二位前缀和预处理即可。

注意空集的情况!!!

  1. //The code is from dawn_sdy
  2. #include<bits/stdc++.h>
  3. #define int long long
  4. using namespace std;
  5. inline int read() {
  6. int x = 0;
  7. char c = getchar();
  8. bool f = 0;
  9. while (!isdigit(c)) f |= (c == '-'), c = getchar();
  10. while (isdigit(c)) x = (x * 10) + (c ^ 48), c = getchar();
  11. return f ? -x : x;
  12. }
  13. const int maxn = 2505;
  14. int n;
  15. struct Point{
  16. int x, y;
  17. }point[maxn];
  18. int lsx[maxn], lsy[maxn], sum[maxn][maxn], ans;
  19. inline bool operator <(Point a, Point b){ return a.y != b.y ? a.y < b.y : a.x < b.x; }
  20. inline int Calc(int x1, int y1, int x2, int y2) { return sum[x2][y2] - sum[x2][y1 - 1] - sum[x1 - 1][y2] + sum[x1 - 1][y1 - 1]; }
  21. signed main(){
  22. // freopen("prob2.in","r",stdin);
  23. // freopen("prob2.out","w",stdout);
  24. n = read();
  25. for(register int i = 1; i <= n; ++i) lsx[i] = point[i].x = read(), lsy[i] = point[i].y = read();
  26. sort(lsx + 1, lsx + n + 1), sort(lsy + 1, lsy + n + 1);
  27. for(register int i = 1; i <= n; ++i) {
  28. point[i].x = lower_bound(lsx + 1, lsx + n + 1, point[i].x) - lsx;
  29. point[i].y = lower_bound(lsy + 1, lsy + n + 1, point[i].y) - lsy;
  30. sum[point[i].x][point[i].y] = 1;
  31. }
  32. for(register int i = 1; i <= n; ++i)
  33. for(register int j = 1; j <= n; ++j) {
  34. sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
  35. }
  36. sort(point + 1, point + n + 1);
  37. for(register int i = 1; i <= n; ++i)
  38. for(register int j = i; j <= n; ++j) {
  39. int minn = min(point[i].x, point[j].x), maxx = max(point[i].x, point[j].x);
  40. ans += Calc(1, point[i].y, minn, point[j].y) * Calc(maxx, point[i].y, n, point[j].y);
  41. }
  42. printf("%lld", ans + 1);
  43. return 0;
  44. }

T3 Prob3

分析

由于只有 两个方向,所以只有 的奶牛与 的奶牛会互相相撞。

把每个奶牛的路径看成一条射线,容易求出所有的交点。

但还有两个问题。

,由于每个奶牛被阻碍后就会停下,所以有可能我们会多算一些交点。

考虑开一个标记数组,标记已经相遇过的线。

但是我们不知道相遇形成的顺序。

但由于只有 方向的线,所以相遇的顺序一定是按坐标从左下到右上的。

即我们按照为第一关键字,为第二关键字,给交点排序即可。

,我们要知道两头奶牛相撞到底是哪头撞的哪头。

这个很简单,算一下走的距离,比较一下就好。

那最后的答案如何算?

考虑由于传递性的存在,设奶牛阻碍了奶牛,可得:

  1. //The code is from dawn_sdy
  2. #include<bits/stdc++.h>
  3. using namespace std;
  4. inline int read() {
  5. int x = 0;
  6. char c = getchar();
  7. bool f = 0;
  8. while (!isdigit(c)) f |= (c == '-'), c = getchar();
  9. while (isdigit(c)) x = (x * 10) + (c ^ 48), c = getchar();
  10. return f ? -x : x;
  11. }
  12. const int maxn = 1005;
  13. int n, lenN, lenE, lenP, Ans[maxn];
  14. bool Vst[maxn];
  15. struct Point {
  16. int id, x, y;
  17. inline void Add(int id0, int x0, int y0) { id = id0, x = x0, y = y0; }
  18. }North[maxn], East[maxn], Cow[maxn];
  19. inline bool operator <(Point a, Point b) { return a.x > b.x && a.y < b.y; }
  20. struct node {
  21. int x, y, idx, idy;
  22. inline void Add(int x0, int y0, int idx0, int idy0) { x = x0, y = y0, idx = idx0, idy = idy0; }
  23. }Point[maxn * maxn];
  24. inline bool operator <(node a, node b){ return a.x != b.x ? a.x < b.x : a.y < b.y; }
  25. int main(){
  26. // freopen("prob3.in","r",stdin);
  27. // freopen("prob3.out","w",stdout);
  28. n = read();
  29. char c;
  30. for(register int i = 1; i <= n; ++i) {
  31. while(!isalpha(c = getchar()));
  32. int x = read(), y = read(); Cow[i].Add(i, x, y);
  33. if(c == 'N') North[++lenN].Add(i, x, y);
  34. else East[++lenE].Add(i, x, y);
  35. }
  36. for(register int i = 1; i <= lenN; ++i)
  37. for(register int j = 1; j <= lenE; ++j)
  38. if(North[i].x > East[j].x && North[i].y < East[j].y) Point[++lenP].Add(North[i].x, East[j].y, East[j].id, North[i].id);
  39. sort(Point + 1, Point + lenP + 1);
  40. for(register int i = 1; i <= lenP; ++i) {
  41. if(Vst[Point[i].idx]||Vst[Point[i].idy]) continue;
  42. int Disx = Point[i].x - Cow[Point[i].idx].x, Disy = Point[i].y - Cow[Point[i].idy].y;
  43. if(Disx < Disy) Vst[Point[i].idy] = 1, Ans[Point[i].idx] += (Ans[Point[i].idy] + 1);
  44. if(Disy < Disx) Vst[Point[i].idx] = 1, Ans[Point[i].idy] += (Ans[Point[i].idx] + 1);
  45. }
  46. for(register int i = 1; i <= n; ++i) printf("%d\n", Ans[i]);
  47. return 0;
  48. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注