【解题报告】2015ACM/ICPC亚洲区沈阳站
来源:互联网 发布:交英语的软件 编辑:程序博客网 时间:2024/04/28 14:01
题目链接
B. Bazinga(HDU5510)
思路
设第i个字符串存储在ss[i][]中。本题最直观最朴素的做法是枚举两个字符串ss[i]和ss[j]
我的做法是,先令所有的ss[i]
例如ss[1] = “ab”, ss[2] = “bc”, ss[3] = “abc”。在ss[1],ss[2]同ss[3]的比较中发现,ss[1]和ss[2]都是ss[3]的子串。对应的位置信息为
代码:
#include <cstdio>#include <cstring>const int maxn = 5e2 + 5, maxLen = 2e3 + 5;char ss[maxn][maxLen];int t, n, ans, next[maxLen], a[maxn][2];void getNext(char* p) { int lp = strlen(p); next[0] = -1; for(int j=0, k=-1; j < lp-1;) { if(k == -1 || p[j] == p[k]) { j++, k++; if(p[j] != p[k]) next[j] = k; else next[j] = next[k]; } else k=next[k]; }}int kmp(char* s, char* p) { int i = 0, j = 0; int ls = strlen(s), lp = strlen(p); for(; i < ls && j < lp;) { if(j == -1 || s[i] == p[j]) i++, j++; else j = next[j]; } if(j == lp) return i - j; else return -1;}int main() { scanf("%d", &t); for(int kase = 1; kase <= t; kase++) { scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%s", ss[i]); } int len = strlen(ss[n]); bool exist = false; // 判断n是否是答案 for(int i = 1; i < n; i++) { getNext(ss[i]); int res = kmp(ss[n], ss[i]); if(res == -1) { exist = true; break; } // 记录位置信息 a[i][0] = res; a[i][1] = res + strlen(ss[i]) - 1; } if(exist) { printf("Case #%d: %d\n", kase, n); continue; } ans = -1; // 枚举两个字符串,比较它们的位置信息 for(int i = n - 1; i > 0; i--) { for(int j = 1; j < i; j++) { if(a[i][0] > a[j][0] || a[i][1] < a[j][1]) { ans = i; i = 0; break; } } } printf("Case #%d: %d\n", kase, ans); } return 0;}
D. Pagodas(HDU 5512)
思路
根据贝祖定理(扩展欧几里德算法的理论基础),对于任意两个整数
代码
#include <bits/stdc++.h>using namespace std;int t, n, a, b, g, ub, times;int main() { scanf("%d", &t); for(int kase = 1; kase <= t; kase++) { printf("Case #%d: ", kase); scanf("%d%d%d", &n, &a, &b); g = __gcd(a, b); ub = n - n % g; times = ub / g - 2; puts(times % 2 ? "Yuwgna" : "Iaka"); } return 0;}
F. Frogs(HDU 5514)
思路(容斥原理)
首先,根据贝祖定理可知,第i只青蛙能够到达的石块的编号组成的数列应是以起点编号0为首项,以
那么这是不是意味着我们可以枚举每只青蛙,然后对每只青蛙对应的等差数列求和,然后再将所有的数列和相加就能得到正确答案了呢?这种思路是不对的,因为这样简单地相加是会有重复的。例如
所以,接下来的问题是要解决重复。对以样例第一组为例,最直观的办法是额外减去
对第一只青蛙我们只需要在最后的结果ans变量中加上第一只青蛙对应的编号数列和即可。然后考虑第二只青蛙,除了加上数列和以外,还要减少一只虚拟青蛙
其实,这样重复加需要减来抵消,重复减又需要加来抵消的情况符合容斥原理的模型(想象求几何图形交的总面积)。实现方法是:记
这个过程像极了求几何图形交的总面积的过程,因此我才将表示某部分是否已经算入ans的标记数组的名字命名为painted。
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 1e4 + 10, maxFac = 1e3;int t, n, m, a, g[maxn], painted[maxFac];vector <int> fac;ll ans;ll sum(ll n, ll d) { return n * (n-1) / 2 * d;}int main() { scanf("%d", &t); for(int kase = 1; kase <= t; kase++) { scanf("%d%d", &n, &m); // 输入数据的同时预处理出g for(int i = 0; i < n; i++) { scanf("%d", &a); g[i] = __gcd(a, m); } fac.clear(); // 枚举m的因数 for(int i = 1; i * i <= m; i++) { if(m % i == 0) { fac.push_back(i); if(i * i != m) { fac.push_back(m / i); } } } sort(fac.begin(), fac.end()); memset(painted, 0, sizeof(painted)); for(int i = 0; i < n; i++) { for(int j = 0; j < fac.size(); j++) { // 初始化painted数组 if(fac[j] % g[i] == 0) { painted[j] = 1; } } } ans = 0; for(int i = 0; i < fac.size(); i++) { if(painted[i] != 0) { // 将数列和加到最后结果中 ans += painted[i] * sum(m / fac[i], fac[i]); // 维护painted数组 for(int j = i + 1; j < fac.size(); j++) { if(fac[j] % fac[i] == 0) { painted[j] -= painted[i]; } } } } printf("Case #%d: %I64d\n", kase, ans); } return 0;}
M.Meeting(HDU5521)
思路
分别以两只牛的起点为起点求两个最短路数组,然后枚举每个点就能找到最好的那个点。注意,如果确定要在某个点相会,一只牛先到了的话需要等另外一只牛。另外,图的每个完全子图都要建边的话复杂度将难以让人忍受所以对于每个完全子图,设置一个虚拟的结点,再从虚拟结点向子图中的所有结点建边,这样建边的复杂度就降低到了线性复杂度。
代码
#include <bits/stdc++.h>using namespace std;typedef long long ll;typedef pair <ll, int> p;const int maxn = 1e5 + 5, maxm = 1e6 + 5;const ll INF = 1e15 + 5;bool vis[maxn + maxm];int t, m, n, si, ti;ll ans, maxTime[maxn];vector <int> vec;// 边的结构体struct edge { int to, dist; edge() {} edge(int to, int dist): to(to), dist(dist) {}};// dijkstra算法模板struct dijkstra { ll d[2][maxn+maxm]; vector <edge> G[maxn+maxm]; void init() { for(int i = 1; i <= n + m; i++) { G[i].clear(); } for(int i = 0; i < 2; i++) { for(int j = 1; j <= n + m; j++) { d[i][j] = INF; } } } void addEdge(int u, int v, int w) { G[u].push_back(edge(v, w)); } bool dfs(int u, int t) { vis[u] = true; if(u == t) return true; bool res = false; for(int i = 0; i < G[u].size(); i++) { int v = G[u][i].to; if(!vis[v]) res |= dfs(v, t); } return res; } void SSSP(int dir, int s) { priority_queue < p, vector<p>, greater<p> > pq; pq.push(p(0, s)); d[dir][s] = 0; while(!pq.empty()) { p node = pq.top(); pq.pop(); int u = node.second; ll dist = node.first; if(d[dir][u] < dist) continue; for(int i = 0; i < G[u].size(); i++) { edge& e = G[u][i]; if(d[dir][e.to] > dist + e.dist) { d[dir][e.to] = dist + e.dist; pq.push(p(d[dir][e.to], e.to)); } } } }}o;int main() { scanf("%d", &t); for(int kase = 1; kase <= t; kase++) { scanf("%d%d", &n, &m); o.init(); for(int i = 1; i <= m; i++) { scanf("%d%d", &ti, &si); for(int v; si--;) { scanf("%d", &v); // 结点向虚拟节点建边 o.addEdge(v, n + i, ti); // 虚拟节点向结点建边 o.addEdge(n + i, v, ti); } } printf("Case #%d: ", kase); memset(vis, 0, sizeof(vis)); bool flag = o.dfs(1, n); if(flag) { // 求两个方向上的最短路数组 o.SSSP(0, 1); o.SSSP(1, n); // 求到每个结点的相会耗时 for(int i = 1; i <= n; i++) { maxTime[i] = max(o.d[0][i], o.d[1][i]); } // 找出最佳方案 ans = *min_element(maxTime + 1, maxTime + n + 1); printf("%I64d\n", ans / 2); vec.clear(); for(int i = 1; i <= n; i++) { if(ans == maxTime[i]) { vec.push_back(i); } } for(int i = 0; i < vec.size(); i++) { printf("%d", vec[i]); putchar(i == vec.size() - 1 ? '\n' : ' '); } } else puts("Evil John"); } return 0;}
(其它题目略)
- 【解题报告】2015ACM/ICPC亚洲区沈阳站
- 【解题报告】2015ACM/ICPC亚洲区上海站
- 2016ACM/ICPC亚洲区沈阳站
- 2017ACM/ICPC亚洲区沈阳站
- Pagodas --(hdu5512)2015ACM/ICPC亚洲区沈阳站
- 2015ACM/ICPC亚洲区沈阳站 HDU
- 【解题报告】2014ACM/ICPC亚洲区鞍山站
- 【解题报告】2014ACM/ICPC亚洲区广州站
- 【解题报告】2015ACM/ICPC亚洲区长春站
- 2016ACM/ICPC亚洲区沈阳站现场赛题解报告
- HDU5950 2016ACM/ICPC亚洲区沈阳站现场赛
- 【HDU 6228、2017ACM/ICPC亚洲区沈阳站】Tree
- 【HDU 6227 2017ACM/ICPC亚洲区沈阳站】Rabbits
- 2017ACM/ICPC亚洲区沈阳站【solved:6 / 13】
- 2016ACM/ICPC亚洲区沈阳站两道水题
- 【解题报告】2014ACM/ICPC亚洲区北京站
- HDU 5512 Pagodas(gcd + 奇偶性判断)——2015ACM/ICPC亚洲区沈阳站
- HDU 5510 Bazinga(KMP)——2015ACM/ICPC亚洲区沈阳站
- Libimseti的用户推荐系统
- 《VR入门系列教程》之14---面向大众的Unity3D
- 如何设计高效合理的MySQl查询语句
- select poll epoll
- Response.AddHeader使用实例
- 【解题报告】2015ACM/ICPC亚洲区沈阳站
- js内置对象详解
- 利用监听者模式实现后台多文件下载的监听
- Android应用程序如何获得系统签名权限02
- innodb与myisam
- 服务器SVN上面的东西检出到本地
- Smarty跳转到页面锚点上
- Windows 10下WLAN突然不能连接(按那个启用禁用蓝牙的按钮也没有用)的问题
- C# Static 使用