【USACO】2017 December Contest, Platinum题解
【比赛经历】
- 大概顺利满分了,就是T2的代码比较难调。
- T2能够直观地反映出GDB和输出调试结合的优越性。
【T1】Standing Out from the Herd
【题目链接】
- 点击打开链接
【题解链接】
- 点击打开链接
【思路要点】
- 后缀的前缀是子串,考虑使用后缀结构来解题。笔者选用的是后缀树。
- 对所有询问串建立多串的后缀树,DFS,在访问一个子树中后缀标记唯一的点时,将其父边的长度加到对应字符串的答案计数器中即可。
- 时间复杂度\(O(\sum|S|)\)。
【代码】
#include<bits/stdc++.h> using namespace std; #define MAXN 200005 #define MAXC 26 template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f; } template <typename T> void write(T x) {if (x < 0) x = -x, putchar('-');if (x > 9) write(x / 10);putchar(x % 10 + '0'); } template <typename T> void writeln(T x) {write(x);puts(""); } struct Suffix_Automaton {int child[MAXN][MAXC];int father[MAXN], depth[MAXN];int root, size, last, n;vector <int> a[MAXN];int colour[MAXN];bool unq[MAXN];long long ans[MAXN];int new_node(int dep) {depth[size] = dep;unq[size] = true;return size++;}void init() {size = 0;root = last = new_node(0);}void addcol(int pos, int col) {if (!unq[pos]) return;if (colour[pos] == 0) colour[pos] = col;else if (col != colour[pos]) unq[pos] = false;}void Extend(int ch, int col) {int np = child[last][ch];if (np) {if (depth[np] == depth[last] + 1) {addcol(np, col);last = np;} else {int nq = new_node(depth[last] + 1);father[nq] = father[np];father[np] = nq;memcpy(child[nq], child[np], sizeof(child[np]));for (int p = last; child[p][ch] == np; p = father[p])child[p][ch] = nq;addcol(nq, col);last = nq;}} else {int np = new_node(depth[last] + 1);int p = last;for (; child[p][ch] == 0; p = father[p])child[p][ch] = np;if (child[p][ch] == np) {addcol(np, col);last = np;return;}int q = child[p][ch];if (depth[q] == depth[p] + 1) {father[np] = q;addcol(np, col);last = np;return;} else {int nq = new_node(depth[p] + 1);father[nq] = father[q];father[np] = father[q] = nq;memcpy(child[nq], child[q], sizeof(child[q]));for (; child[p][ch] == q; p = father[p])child[p][ch] = nq;addcol(np, col);last = np;}}}void insert(char *s, int col) {int len = strlen(s + 1);last = root; ans[col] = 0;for (int i = 1; i <= len; i++)Extend(s[i] - 'a', col);n = col;}void work(int pos) {for (unsigned i = 0; i < a[pos].size(); i++) {work(a[pos][i]);if (unq[a[pos][i]]) addcol(pos, colour[a[pos][i]]);else unq[pos] = false;}if (pos != 0 && unq[pos]) ans[colour[pos]] += depth[pos] - depth[father[pos]];}void solve() {for (int i = 1; i < size; i++)a[father[i]].push_back(i);work(0);for (int i = 1; i <= n; i++)printf("%lld\n", ans[i]);} } SAM; char s[MAXN]; int main() {freopen("standingout.in", "r", stdin);freopen("standingout.out", "w", stdout);SAM.init();int n; read(n);for (int i = 1; i <= n; i++) {scanf("%s", s + 1);SAM.insert(s, i);}SAM.solve();return 0; }
【T2】Push a Box
【题目链接】
- 点击打开链接
【题解链接】
- 点击打开链接
【思路要点】
- 首先,如果我们已经得到了每一个点在删去之后其上下左右四个点的连通性,那么简单的记忆化搜索即可解决本题。
- 如何求解这个信息呢?我们发现,“删去一个点”的前提与点双联通分量的定义十分类似,我们考虑对传统的Tarjan算法进行改编,来求得上述信息。
- 具体来说,在一个点刚刚被访问时,它已经被访问过的相邻的点以及能够与其在DFS树上的祖先联通的点是在删去这个点后依然相互联通的;在结束对它的一个子节点的访问时,我们可以得到,其他在访问这个子节点时新被访问的子节点应当与这个子节点在删去这个点时相互联通。
- 这个过程比较难以说清,如有看不懂的读者可以自行阅读下文的代码。在这个程序中,笔者对每一个点开设了一个大小为4的数组(Col数组),如果某个点的两个方向在删去它之后依然联通,那么对应位置的值相等。另外,笔者考试时的调试函数也保留在了这个程序中。
- 时间复杂度\(O(NM+Q)\)。
【代码】
#include<bits/stdc++.h> using namespace std; #define MAXN 1505 template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f; } template <typename T> void write(T x) {if (x < 0) x = -x, putchar('-');if (x > 9) write(x / 10);putchar(x % 10 + '0'); } template <typename T> void writeln(T x) {write(x);puts(""); } int dx[4] = {0, 0, 1, -1}; int dy[4] = {1, -1, 0, 0}; int pr[4] = {1, 0, 3, 2}; //0: Right, 1: Left, 2: Down, 3: Up. char mp[MAXN][MAXN]; int n, m, q, sx, sy, tx, ty, sd; int num[MAXN][MAXN], col[MAXN][MAXN][4]; int timer, dfn[MAXN][MAXN], low[MAXN][MAXN]; bool tv[MAXN][MAXN], visited[MAXN][MAXN][4]; bool valid(char x) {return x == '.' || x == 'A' || x == 'B'; } void work(int px, int py, int fx, int fy, int fd) {dfn[px][py] = low[px][py] = ++timer;int tmp = 0;if (fd != -1) {col[px][py][fd] = ++tmp;for (int j = 0; j <= 3; j++) {int tx = px + dx[j];int ty = py + dy[j];if (!valid(mp[tx][ty])) continue;if (dfn[tx][ty] && col[px][py][j] == 0)col[px][py][j] = tmp;}}for (int i = 0; i <= 3; i++) {int tx = px + dx[i];int ty = py + dy[i];if (tx == fx && ty == fy) continue;if (!valid(mp[tx][ty])) continue;if (dfn[tx][ty]) {low[px][py] = min(low[px][py], dfn[tx][ty]);continue;}work(tx, ty, px, py, pr[i]);low[px][py] = min(low[px][py], low[tx][ty]);if (low[tx][ty] >= dfn[px][py]) {col[px][py][i] = ++tmp;for (int j = i + 1; j <= 3; j++) {int tx = px + dx[j];int ty = py + dy[j];if (!valid(mp[tx][ty])) continue;if (dfn[tx][ty] && col[px][py][j] == 0)col[px][py][j] = tmp;}} else {col[px][py][i] = 1;for (int j = i + 1; j <= 3; j++) {int tx = px + dx[j];int ty = py + dy[j];if (!valid(mp[tx][ty])) continue;if (dfn[tx][ty] && col[px][py][j] == 0)col[px][py][j] = 1;}}} } void printcol() {for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {for (int k = 0; k <= 3; k++)printf("%d", col[i][j][k]);printf(" ");}printf("\n");} } void getsd(int px, int py, int ld) {tv[px][py] = true;if (px == tx && py == ty) sd = ld;for (int i = 0; i <= 3; i++) {int tx = px + dx[i];int ty = py + dy[i];if (!valid(mp[tx][ty]) || tv[tx][ty]) continue;getsd(tx, ty, pr[i]);} } void dfs(int px, int py, int ld) {visited[px][py][ld] = true;int td = pr[ld];if (valid(mp[px + dx[td]][py + dy[td]]) && !visited[px + dx[td]][py + dy[td]][ld]) {dfs(px + dx[td], py + dy[td], ld);}for (int i = 0; i <= 3; i++)if (!visited[px][py][i] && col[px][py][i] == col[px][py][ld]) {dfs(px, py, i);} } void printvis() {for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {for (int k = 0; k <= 3; k++)printf("%d", visited[i][j][k]);printf(" ");}printf("\n");} } int main() {freopen("pushabox.in", "r", stdin);freopen("pushabox.out", "w", stdout);read(n), read(m), read(q);for (int i = 1; i <= n; i++)scanf("%s", mp[i] + 1);for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)if (dfn[i][j] == 0 && mp[i][j] != '#') {work(i, j, 0, 0, -1);}for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++) {if (mp[i][j] == 'A') sx = i, sy = j;if (mp[i][j] == 'B') tx = i, ty = j;}sd = -1;getsd(sx, sy, -1);if (sd == -1) visited[tx][ty][0] = true;else dfs(tx, ty, sd);for (int i = 1; i <= q; i++) {int x, y;read(x), read(y);bool flg = false;for (int j = 0; j <= 3; j++)flg |= visited[x][y][j];if (flg) printf("YES\n");else printf("NO\n");}return 0; }
【T3】Greedy Gift Takers
【题目链接】
- 点击打开链接
【题解链接】
- 点击打开链接
【思路要点】
- 无法得到礼物的人一定是某一段右端点为序列末尾的区间中的人。
- 进一步地,如果在位置1到位置\(j\)中一共出现了\(i\)个大于等于\(N-i\)的数,那么\(j+1\)号位的人无法得到礼物。
- 依次扫描数列,用线段树维护一个支持区间减法的序列,在第一次出现一个\(i\)满足一共出现了\(i\)个大于等于\(N-i\)的数时得到答案。
- 时间复杂度\(O(NLogN)\)。
【代码】
#include<bits/stdc++.h> using namespace std; #define MAXN 200005 template <typename T> void read(T &x) {x = 0; int f = 1;char c = getchar();for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';x *= f; } template <typename T> void write(T x) {if (x < 0) x = -x, putchar('-');if (x > 9) write(x / 10);putchar(x % 10 + '0'); } template <typename T> void writeln(T x) {write(x);puts(""); } struct SegmentTree {struct Node {int lc, rc;int Min, tag;} a[MAXN];int n, root, size;void pushdown(int root) {if (a[root].tag) {int tmp = a[root].tag, pos;pos = a[root].lc;a[pos].Min -= tmp;a[pos].tag += tmp;pos = a[root].rc;a[pos].Min -= tmp;a[pos].tag += tmp;a[root].tag = 0;}}void update(int root) {a[root].Min = min(a[a[root].lc].Min, a[a[root].rc].Min);}void build(int &root, int l, int r) {root = ++size;if (l == r) {a[root].Min = n - l;return;}int mid = (l + r) / 2;build(a[root].lc, l, mid);build(a[root].rc, mid + 1, r); update(root);}void init(int x) {n = x; size = root = 0;build(root, 0, n - 1);}void modify(int root, int l, int r, int ql, int qr, int d) {if (l == ql && r == qr) {a[root].tag += d;a[root].Min -= d;return;}pushdown(root);int mid = (l + r) / 2;if (mid >= ql) modify(a[root].lc, l, mid, ql, min(mid, qr), d);if (mid + 1 <= qr) modify(a[root].rc, mid + 1, r, max(mid + 1, ql), qr, d);update(root);}void solve(int x) {modify(root, 0, n - 1, 0, x, 1);}int query() {return a[root].Min;} } SMT; int main() {freopen("greedy.in", "r", stdin);freopen("greedy.out", "w", stdout);int n; read(n);SMT.init(n);for (int i = 1; i <= n; i++) {int x; read(x);SMT.solve(x);if (SMT.query() == 0) {printf("%d\n", n - i);return 0;}}return 0; }
【USACO】2017 December Contest, Platinum题解相关推荐
- USACO 2017 December Contest Platinum T3: Greedy Gift Takers
题目大意 有 N(1≤N≤1e5)头牛按顺序排成一列,编号从 1 到 N,1 号牛在队头,N 号牛在队尾. 每次位于队头的牛 i 拿到一个礼物,然后插入到从队尾数ci头牛之前的位置..举个栗子: 初 ...
- USACO 2022 December Contest, BronzeProblem 1. Cow College 题解
以下是2022年-2023年USACO赛季第一个月的青铜组第一题,可以使用"计数数组+打擂台找最值"的思想,需要考生掌握一点算法才能通关.文章引用了官网题面,提供思考思路和代码,代 ...
- 【USACO 2017 December Gold】A Pie for a Pie题解
Description Bessie and Elsie have each baked N pies (1≤N≤10^5). Each of the 2N pies has a tastiness ...
- USACO 2020 December Contest, BronzeProblem 2. Daisy Chains题解
题目描述: 每天,作为她绕农场行走的一部分,奶牛 Bessie 会经过她最喜爱的草地,其中种有 N 朵花(五颜六色的雏菊),编号为1-N(1≤N≤100),排列成一行.花 i 有 pi 朵花瓣(1≤p ...
- USACO 2018 January Contest Platinum A: Lifeguards 题解
将所有的区间按左端点从小到大排序 我们处理那些被完全包含的区间,这些区间即使删除也不会使答案变坏 这样先删一波,如果发现这种小区间的个数多于k,就可以直接算答案了 否则我们要dp 设dp[i][j]为 ...
- USACO 2020 December Contest, BronzeProblem 1. Do You Know Your ABCs?
QUESTION Farmer John 的奶牛正在 "mooZ" 视频会议平台上举行每日集会.她们发明了一个简单的数字游戏,为会议增添一些乐趣. Elsie 有三个正整数 A.B ...
- Promotion Counting【USACO 2016 January Contest, Bronze】
今天来分享一下我做过的几道Usaco的比较简单的题,Usaco是美国的一个c++竞赛比赛,但是全球各地的人都可以参加,Usaco没有监考,全凭诚信,但是你拿着这个 作弊 借鉴来的成绩,所有美国的大学都 ...
- USACO 2018 January Contest
USACO 2018 January Contest 比赛链接 T1 MooTube 题目链接 题目大意:给定一个图,两个点之间的距离是他们路径上边权的最小值.给定一个起点,求距离大于等于K的点有几个 ...
- USACO 2018 FEBURARY CONTEST :SILVER T1
USACO 2018 February Contest, Silver Problem 1. Rest Stops Farmer John and his personal trainer Bessi ...
最新文章
- 正则表达式校验IP地址
- 移动端页面输入法挡住input输入框的解决方法
- 2018.12.22 spoj7258 Lexicographical Substring Search(后缀自动机)
- Android:Margin和Padding
- linux下添加服务,Linux下添加服务
- 计算机目标导学方法,计算机教学计划
- FTPClient.listFiles()不能获取目录里的文件
- linux上数据库导入与导出(mysql)
- Javassist-手写字节码文件
- 概率论 马尔可夫 切比雪夫等定理的解释
- 笔记本vmware利用无线网卡上网设置
- vue 加headers_vue上传图片设置headers表头信息
- python中、常见的结构化数据不包括_数据分析的主要内容仍是结构化计算_数据分析师...
- 四六级分数竟是这样算出来的!交白卷都不会得零分 (转)
- ZlycerQan的 八云蓝(ran )
- vue实现一个类似浏览器搜索功能(ctrl + f)
- 大数据实战项目 -- 离线数仓
- IO复用模型同步,异步,阻塞,非阻塞及实例详解
- mtk平台的gpio控制
- Android 语音播报之项目实战
热门文章
- 数据分析 常用的数据指标
- nvme-cli常用指令
- QE动力学矩阵文件的主要内容及单位
- cannot dynamically load executable的尴尬经历
- nant_NAnt和FxCopCmd今天我在NAnt和
- 科研人必备论文小技巧——word分分钟自动修改插入的参考文献、附图和表格的插入技巧
- matlab 医学断层图像,利用MATLAB实现CT断层图像的三维重建
- UNIFI 多wan端口转发设置
- 【优化求解】基于多策略黑猩猩优化算法求解单目标优化问题附matlab代码
- sketch制作Android动画,Sketch制作GIF动画——基础篇(改良版)