2017-2018 ACM-ICPC, Asia Daejeon Regional Contest

ECFINAL PK赛。


C
签到题。
DAG上的dp。

D
签到题。
根据数据范围可知暴力即可。

F
哲学题。
简单递归,甚至没有前几天的牛客21小白赛的B麻烦。


补题

这套题在之前补过一部分,好像是这十套里补过的唯一一套。

H
如果mmm串在nnn串的kkk位置,那么获胜的情况为∑i=1m[b[i]战胜a[k+i]]\sum_{i=1}^{m}[b[i]战胜a[k+i]]i=1∑m​[b[i]战胜a[k+i]]
枚举你出的三种拳,将序列中对应的位置设为1,其余位置则设为0;相应的,在电脑的出拳序列中将会输的位置设为1,其余位置设为0,那么在该情况喜爱,获胜的种数即为∑i=1ma[i+k]∗b[i]\sum_{i=1}^ma[i+k]*b[i]i=1∑m​a[i+k]∗b[i]

将bbb序列做转置得到b′b'b′,那么上述表达式则转化为卷积形式
∑i=1ma[i+k]∗b′[m+1−i]\sum_{i=1}^ma[i+k]*b'[m+1-i]i=1∑m​a[i+k]∗b′[m+1−i]
做一次fft然后获取第m+1+km + 1 + km+1+k项的系数即可得到在所有位置kkk开始比赛时的获胜数.

所以对每一种出拳做一次fft,求最大值之和即可获取最终答案。

有一个地方要注意,题目说明这两个序列并不需要完全包含,所以上述的位置kkk可以取遍k=1,2,…,n.k=1,2,\dots,n.k=1,2,…,n. 相应的,序列数组a,ba,ba,b也要扩大范围来空设一部分元素。

I
KMP算法。
正着弄不方便,首先我们先将原序列翻转,做一次kmp得到next数组。然后我们枚举循环数序列的终点,画图求解后容易知道循环节的长度就是i−next[i].i-next[i].i−next[i]. 不过具体的表达式还是要根据next数组的具体意义等等来决定。

这道题好像在xdoj上有,但是我当时不会做。

总之这道题还是一个很巧妙的KMP应用题,如果在画图的时候用循环节一段段的表示的话其实想到用KMP也不是特别困难的事情。

K
构造一段方向不变,长度可以改变的折线段,要求直线间两两不能相交。
水题。不过当时场上被I打蒙了,所以这个题看都没有看一眼…
两种构造办法都可以成功,一个是从上限nnn进行构造,一个是从下限111进行构造,记录当前图形的四个边界后采用螺线形进行扩散即可。

B
不算难的一道暴力搜索题。
因为发现哪怕没有重力的限制,最多的状态总数也只有316=4e73^{16}=4e7316=4e7,再加上我们有重力约束、起始点的约束可以有效的剪不少枝,所以时间是没有太大的限制的,下面要做的就是仔细地写好这个dfs模拟。

int start, xx, yy;
int a[4][4];
unordered_set<int> s;int range(int x, itn y){if(x >= 0 && y >= 0 && x < 4 && y < 4) return 1;return 0;
}int ok(int x, int y, int dx, itn dy){int x1 = x + dx, x2 = x - dx, y1 = y + dy, y2 = y - dy;if(range(x, y) && range(x1, y1) && range(x2, y2) && a[x][y] == a[x1][y1] && a[x1][y1] == a[x2][y2]) return 1;return 0;
}int check(int x, int y, int dx, int dy){if(ok(x, y, dx, dy) || ok(x - dx, y - dy, dx, dy) || ok(x + dx, y + dy, dx, dy)) return 1;return 0;
}bool isok(int x, int y, int op){if(a[x][y] == op && (check(x, y, 1, 0) || check(x, y, 0, 1) || check(x, y, 1, 1) || check(x, y, 1, -1)))return 1;return 0;
}int has(){int x, y;int res = 0;for(int i = 15; i >= 0; i--){x = i / 4; y = i % 4;res *= 3;res += a[x][y];}return res;
}void dfs(int x, int op){int i;for(i = 0; i < 4; i++) if(a[i][x] == 0) break;if(i == 4) return ;a[i][x] = op;if(isok(i, x, op)){if(op == 1){a[i][x] = 0; return ;}else{if(i == xx && x == yy){s.insert(has()); a[i][x] = 0; return;}else{a[i][x] = 0; return ;}}}if(i == xx && x == yy && op == 1){a[i][x] = 0; return ;}for(int j = 0; j < 4; j++) dfs(j, 3 - op);a[i][x] = 0;
}int main(){//    Fast;scanf("%d %d %d", &start, &xx, &yy);start--; xx--; yy--;dfs(start, 1);printf("%d\n", (int)s.size());return 0;
}

代码粗理不粗,感觉写的还是比较有条理的…

最开始写完后怎么调都还是结果不对,仔细研究(小数据对拍1 2 1)后发现我没有判断白子在其余位置获胜时的情况,所以结果总是大于正确结果。

对于这种要仔细分类讨论的情况,一定要注意条件的充要转化!

E
结合之前暑训的一部分内容(2019暑训8月5号 网络流)和一个非常好的博客网络流基础,我复习了一下网络流算法的思想。

现在再看网络流相关有了更深刻的理解。之前并没有很深刻地理解以增广路为核心的FF算法、EK算法和Dinic算法,刚刚温故知新后发现增广路的重要地位。其实求解最大流最朴素的办法就是尝试找一条路其流量均严格小于其流量,这样就可以对这条路扩流;不断尝试直到没有一条增广路后我们就得到了最大流。而EK算法就是避免找增广路时越找越远,所以用bfs进行分层,分完层再用dfs进行扩流;不过EK算法的扩流是针对某一条可行流的扩流,每次对一条可行流扩流都会进行一次bfs,bfs的分层结果没有充分被利用;而Dinic算法则在bfs之后进行多路扩流,将bfs的结果完全的利用起来,这样就完成了算法效率的提升。

回到本题,对于某一条边,如何才可以保证其被一颗MST包含?当然应该使得其余比他权值低的边都被删除,这就是一个最小割问题。
当求解某一条对应的花费时,开设一个新边集数组,用来记录生成的网络流的边。我们遍历所有原始边,如果其权值严格小于当前边的权值,那么就在网络图中连一条对应方向、权值为1的边,同时加上一条权值为0的反向边;网络图生成完后,只需要求解从该选取的边的两个端点作为源点和汇点的最大流,这就是必须要删去的边的个数。

因为采取star存图,所以组成无向边的一组有向边会在上述遍历过程中分别被添加一次,也就是总共会有4条”重叠的“边。不过在求解最大流的时候,只有一组边被用到,根据链式前向星的性质知即边i和边i ^ 1。
也因此,网络图的边应该开maxe<<2maxe << 2maxe<<2,而原始边集只需要开maxe<<1maxe << 1maxe<<1,TLE7就是因为网络图的大小没有开够。

AC代码

const int maxn = 1e2 + 10;
const int maxe = 5e2 + 10;struct star{int from, to, w, next;
};int head[maxn], top = 0;
star edge[maxe << 1];int first[maxn], ttt = 0;
star net[maxe << 2];void add(int u, int v, int w, int *head, int &top, star *edge){edge[top].to = v;edge[top].from = u;edge[top].w = w;edge[top].next = head[u];head[u] = top++;
}void netInsert(int u, int v, int w){add(u, v, w, first, ttt, net);add(v, u, 0, first, ttt, net);
}int dis[maxn];
queue<int> q;
int bfs(int s, int t, int *head, star *edge){memset(dis, -1, sizeof dis);while(!q.empty()) q.pop();q.push(s); dis[s] = 0;while(!q.empty()){int temp = q.front(); q.pop();for(int i = head[temp]; ~i; i = edge[i].next){int to = edge[i].to;if(dis[to] == -1 && edge[i].w != 0){q.push(to);dis[to] = dis[temp] + 1;}}}return dis[t] != -1;
}itn dfs(int s, int t, int maxflow, int *head, star *edge){if(s == t || maxflow == 0) return maxflow;int ans = 0;for(int i = head[s]; ~i; i = edge[i].next){int to = edge[i].to;if(dis[to] != dis[s] + 1 || edge[i].w == 0 || ans >= maxflow) continue;int f = dfs(to, t, min(edge[i].w, maxflow - ans), head, edge);edge[i].w -= f; edge[i ^ 1].w += f;ans += f;}return ans;
}int dinic(int s, int t){int ans = 0;while(bfs(s, t, first, net))ans += dfs(s, t, 0x3f3f3f3f, first, net);return ans;
}int cal(int x){memset(first, -1, sizeof first); ttt = 0;for(int i = 0; i < top; i++) if(edge[i].w < edge[x].w)netInsert(edge[i].from, edge[i].to, 1);return dinic(edge[x].from, edge[x].to);
}int main(){//    Fast;memset(head, -1, sizeof head);memset(first, -1, sizeof first);int n, m; scanf("%d %d", &n, &m);for(int i = 0; i < m; i++){int u, v, w;scanf("%d %d %d", &u, &v, &w);add(u, v, w, head, top, edge); add(v, u, w, head, top, edge);}itn ans = 0;for(int i = 0; i < top; i += 2) ans += cal(i);printf("%d\n", ans);return 0;
}

G
也是一道场上连看都没看一眼的不算太难的题目。

如果没有理解错,应该就是之前因为CF某个题而学到的扫描线算法

将所有的拐点按照x坐标排序,维护up和down的值,不断更新答案和个数即可。

尽管如此,这道题还是耗费了我好久好久的时间debug,最后还是对拍才知道自己为什么永久WA3了…

坑点

  • 注意题目允许两种楼梯存在,当两种单调性不同的楼梯交错时一定不会产生闭合区域,这里需要分类讨论。 (sample2对应的情况)

  • 最开始的时候疑惑在最后如果出现infinite的区域该怎么办,仔细读题后注意到约束词closed,那么那些无穷大的边界区域就不予考虑,因而我们对区域个数cnt进行计数的时候只好在出现down>=updown >= updown>=up 后即出现闭合后才能加1。不过,我最开始只关注到了右无穷的边界问题,在循环外加上了一句闭合判断,并没有注意到左无穷的边界问题,从而导致了一屏幕的WA test3…在考虑左无穷区域的时候,只有当左边出现过闭合条件down>=updown >=updown>=up 后才可以开始计数,不然这些区域都是左无穷的一部分。

尽管这道题初看下来还算比较简单,但是还是有一两个小地方要注意到并且考虑清楚的…

还是读题不够细致,考虑情况不够周到,太菜了…

代码

struct Node{ll x, y;int op;
};const int maxn = 25e3 + 10;
itn n, m;
Node node[maxn << 2];
int top = 0;
ll up, down;bool cmp(Node a, Node b){if(a.x != b.x) return a.x < b.x;return a.y < b.y;
}void update(int i){if(node[i].op) up = node[i].y;else down = node[i].y;
}int main(){//    Fast;scanf("%d %d", &n, &m);int x, y, flag = 1;scanf("%lld", &down);for(int i = 0; i < n; i++){scanf("%d %d", &x, &y);node[top].x = x; node[top].y = y; node[top].op = 0;top++;}scanf("%lld", &up);for(int i = 0; i < m; i++){scanf("%d %d", &x, &y);node[top].x = x; node[top].y = y; node[top].op = 1;top++;}flag ^= (node[0].y - down > 0);flag ^= (node[n].y - up > 0);//特判单调性不同的情况。if(!flag){puts("0 0");return 0;}sort(node, node + top, cmp);int pre = -1, preflag = 0;ll res = 0, ans = 0, cnt = 0;for(int i = 0; i < top; i++){//存在区域 && i != 0 && 并不是左无穷区域if(up > down){if(~pre && preflag) res += (node[i].x - pre) * (up - down);}else{preflag = 1;if(res) cnt++;ans += res; res = 0;}update(i);while(i + 1 < top && node[i].x == node[i + 1].x){update(++i);}pre = (int)node[i].x;}if(down >= up){if(res) cnt++;ans += res;}printf("%lld %lld\n", cnt, ans);return 0;
}

参考博客:
「备战PKUWC2018」2017-2018 ACM-ICPC, Asia Daejeon Regional Contest

2017-2018 ACM-ICPC, Asia Daejeon Regional Contest (大部分题解)相关推荐

  1. 2016 ACM / ICPC Asia dalian Regional Contest 题解(11 / 11)【每日亿题2021 / 2 / 17】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 A .(2017 ACM ICPC dalian H)To begin or not to be ...

  2. 2017 ACM ICPC Asia Shenyang Regional Contest 题解(10 / 13)【每日亿题2 / 16】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 A.(2017 ICPC shenyang I)Little Boxes B.(2017 ICP ...

  3. 2017-2018 ACM-ICPC, Asia Daejeon Regional Contest 一些题解

    D. Happy Number(solved by w222222s) 妥妥的水题,模拟一下就行了 #include <bits/stdc++.h> #include <cstrin ...

  4. 2018 ICPC Asia Jakarta Regional Contest

    2018 ICPC Asia Jakarta Regional Contest 题号 题目 知识点 难度 A Edit Distance B Rotating Gear C Smart Thief D ...

  5. The 2019 ICPC Asia Shanghai Regional Contest

    The 2019 ICPC Asia Shanghai Regional Contest 题号 题目 知识点 A Mr. Panda and Dominoes B Prefix Code C Maze ...

  6. 2017-2018 ACM-ICPC, Asia Daejeon Regional Contest

    2017-2018 ACM-ICPC, Asia Daejeon Regional Contest 题号 题目 难度 知识点 A Broadcast Stations B Connect3 C Gam ...

  7. 【题目记录】——The 2021 ICPC Asia Jinan Regional Contest

    文章目录 C Optimal Strategy 组合数 H Game Coin K Search For Mafuyu 欧拉序列 题目集地址 The 2021 ICPC Asia Jinan Regi ...

  8. 2019-2020 ICPC Asia Xuzhou Regional Contest【徐州现场赛】

    题目: 209-2020 ICPC Asia Xuzhou Regional Onsite Contest E. Multiply 题意: 找到最大的 i 使得 z*x^i 是 y! 的因子 分析: ...

  9. 2018 ICPC Asia Jakarta Regional Contest J. Future Generation 状压dp

    传送门 文章目录 题意: 思路: 题意: 给你nnn个串,字符集是a−za-za−z,让你在每个串种选择一个子序列,保证对于i<j,si<sji<j,s_i<s_ji<j ...

最新文章

  1. Leetcode: Maximal Rectangle
  2. 企业进销存管理系统_攻略 | 七巧Plus定制您的专属进销存管理系统
  3. java numberutil_NumberUtil
  4. 海信信号机与铭达倒计时通信对接配置
  5. 4:springApplication.run 原理
  6. 主页是单一的HTML文件,什么是主页,下列说法最为准确的是 _____。
  7. Mac 生成SSH Key
  8. 【电信增值业务学习笔记】3 语音类增值业务
  9. A Spy in the Metro UVA - 1025
  10. 用openssh下的sftp通过chroot控制用户
  11. win10下添加ssh服务
  12. 使用git向远程库发布项目和下载项目步骤,结合gitee部署远程库,HTTPS\SHH上传下载情况详解
  13. 二倍精灵图的做法(以firework为例)
  14. 搜索引擎市场份额2018.3
  15. iOS逆向(7)-LLDB,自制LLDB脚本,窜改微信红包金额
  16. php amp 转义,HTML转义和反转义
  17. VIM 参 考 手 册
  18. Windows 10配置CUDA 9.2
  19. OpenCV Error:Insufficient memory(Failed to allocate 1244164 bytes)
  20. html清除浮动的那一块区域,CSS中的BFC,外边距折叠,清除浮动

热门文章

  1. Win10 突破20%共享大关
  2. WebSocket 简述
  3. python之基础语法常见错误提示总结
  4. 小红书笔记上精选方法技巧有哪些
  5. 12.面向对象(继承/super/接口/抽象类)
  6. PMOS双电源供电隔离电路(USB接入为电池充电 电池断开供电)
  7. 计算机打不开网络共享,电脑的网络和共享中心打不开,网络发现又没打开,..._网络编辑_帮考网...
  8. 脚本案例互联网赚钱怎么赚钱?一切都需要引流脚本
  9. 美国圣诞8日西海岸自驾游
  10. git与github从入门到精通