BestCoder Round #55 解题报告
2015-09-14 23:53
232 查看
A
Source
hdu 5432题意
给你几个底面是正方形的锥体(金字塔),平放于地面,水平切一刀,问切在多高的位置可以使得分离开的两部分体积之和相同。分析
显然是有单调性的,直接二分高度就好了。其他人求体积的做法好像很厉害,待会研究下。。
代码
/************************************************************************* > File Name: a.cpp > Author: james47 > Mail: > Created Time: Sat Sep 12 19:15:02 2015 ************************************************************************/ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const double eps = 1e-5; int T, n; int a[11000], b[11000]; int main() { scanf("%d", &T); while(T--){ scanf("%d", &n); int mx = 0; for (int i = 0; i < n; i++){ scanf("%d", &a[i]); mx = max(a[i], mx); } for (int i = 0; i < n; i++) scanf("%d", &b[i]); long long tot = 0; // /3 for (int i = 0; i < n; i++) tot += (long long)b[i] * b[i] * a[i]; double l = 0.0, r = mx, need = (double)tot/6; while(fabs(r - l) >= eps){ double mid = (l + r) / 2.0; double sum = 0; for (int i = 0; i < n; i++){ if (mid < a[i]){ double h = (double)a[i] - mid; double w = b[i] * h / a[i]; sum += h * w * w / 3; } } if (fabs(sum - need) < eps){ l = mid; break; } if (sum < need) r = mid; else l = mid; } printf("%d\n", (int)l); } return 0; }
B
Source
hdu 5433题意
直接看题吧。。分析
没什么好说的。。dp[x][y][k]表示走到(x, y),剩余k斗志的最小花费体力,然后相当于求最短路咯。trick在于初始斗志为0一律无解,即使起终点重合。代码
/************************************************************************* > File Name: b.cpp > Author: james47 > Mail: > Created Time: Sat Sep 12 19:40:44 2015 ************************************************************************/ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const double eps = 1e-6; int dx[] = {1, -1, 0, 0}; int dy[] = {0, 0, 1, -1}; struct node{ int x, y, k; node(){} node(int x, int y, int k): x(x), y(y), k(k){} }; const int mod = 55*55*55*4; int T; char mp[55][55]; int n, m, tot; int stx, sty, edx, edy; double dp[55][55][55]; bool inq[55][55][55]; node q[mod+5]; int main() { scanf("%d", &T); while(T--){ scanf("%d %d %d", &n, &m, &tot); for (int i = 0; i < n; i ++) scanf("%s", mp[i]); scanf("%d %d %d %d", &stx, &sty, &edx, &edy); if (tot == 0){ puts("No Answer"); continue; } stx --, sty --, edx --, edy --; for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) for (int k = 0; k <= tot; k++){ dp[i][j][k] = 1e10; inq[i][j][k] = false; } int head = 0, tail = 0; dp[stx][sty][tot] = 0.0; inq[stx][sty][tot] = true; q[tail++] = node(stx, sty, tot); while(head != tail){ node u = q[head++]; if (head == mod) head = 0; for (int i = 0; i < 4; i++){ int x = u.x + dx[i], y = u.y + dy[i]; if (x < 0 || y < 0 || x >= n || y >= m) continue; if (mp[x][y] == '#') continue; // printf("%d\n", u.k); // printf("%.2f\n", (double)abs(mp[x][y] - mp[u.x][u.y])/u.k); double tmp = dp[u.x][u.y][u.k] + (double)abs(mp[x][y] - mp[u.x][u.y])/u.k; if (tmp + eps < dp[x][y][u.k-1]){ dp[x][y][u.k-1] = tmp; if (x != edx || y != edy){ if (u.k-1 != 0 && !inq[x][y][u.k-1]){ inq[x][y][u.k-1] = true; q[tail++] = node(x, y, u.k-1); if (tail == mod) tail = 0; } } } } inq[u.x][u.y][u.k] = false; } double ans = 1e10; for (int i = 0; i <= tot; i++) ans = min(ans, dp[edx][edy][i]); if (fabs(ans - 1e10) < eps) puts("No Answer"); else printf("%.2f\n", ans); } return 0; }
C
Source
hdu 5434题意
出题事故!所以后面的题意没有卵用:在n*m的棋盘上放小象,小象可以攻击四个斜方向的位置。如果有公共边,可以变为合体象,相当于攻击范围变小。合法方案要求摆放的象不会互相攻击,求方案数。n很大,m<=7。分析
说了一堆实际上都是扯淡。。因为按照题意这种是合法的,P为象,S不放:
PPP
PSP
PPS
按照数据范围肯定是状压dp然后矩阵快速幂,但是如果这种摆放合法,状态就比较麻烦,还得记录连通性。
但实际上不用。。两行之间只要考虑斜对着的位置。。(i, j)和(i+1, j+1)同时放,必须有(i+1, j)或者(i, j+1)。大概就是这样。。题目出得不太对。。
代码
/************************************************************************* > File Name: hdu_5434.cpp > Author: james47 > Mail: > Created Time: Mon Sep 14 23:00:50 2015 ************************************************************************/ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int mod = 1000000007; const int MAXN = 130; int N; struct matrix{ int a[MAXN][MAXN]; friend matrix operator *(const matrix& a, const matrix& b){ matrix ret; for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) ret.a[i][j] = 0; for (int i = 0; i < N; i++) for (int j = 0; j < N; j++){ for (int k = 0; k < N; k++){ ret.a[i][k] = ((long long)a.a[i][j] * b.a[j][k] + ret.a[i][k]) % mod; } } return ret; } matrix pow(int exp){ matrix ret, tmp = *this; for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) ret.a[i][j] = i==j; for (; exp; exp >>= 1){ if (exp&1) ret = ret * tmp; tmp = tmp * tmp; } return ret; } } mat; int n, m; bool ok(int x, int y){ for (int i = 0; i < m; i++){ if (x&(1<<i)){ if (i != 0){ if ((y&(1<<i-1)) && !(y&(1<<i)) && !(x&(1<<i-1))) return 0; } if (i != m-1){ if ((y&(1<<i+1)) && !(y&(1<<i)) && !(x&(1<<i+1))) return 0; } } } return 1; } int main() { while(scanf("%d %d", &n, &m) != EOF){ N = 1 << m; for (int i = 0; i < N; i++) for (int j = 0; j < N; j++){ if (ok(i, j)) mat.a[i][j] = 1; else mat.a[i][j] = 0; } mat = mat.pow(n); int ans = 0; for (int i = 0; i < N; i++){ ans += mat.a[i][0]; if (ans >= mod) ans -= mod; } printf("%d\n", ans); } return 0; }
D
Source
hdu 5435题意
对整数x,定义F(x)为其十进制各位的异或和。给a和b,求a到b所有数的F(x)的和。a和b长度小于100000。分析
首先容易发现 0 <= F(x) <= 15。然后我们统计[0, A]每个F(x)的值各有多少个x就好了。做法一:
dp[len][pre]表示[0, 10^len)的数,之前高位异或和为pre,最后得到的异或和为[0..15]的数有多少个。也就是说每个dp[i][j]是一个int数组。时间复杂度O(10^5 * 16 * 9)。然后MLE。。
做法二:
dp[len][pre]表示[0, 10^len)的数,之前高位异或和为pre,最后得到异或和为0的数有多少个。相当于调用16次dfs函数,每次不同的初始pre。时间复杂度相同,内存除以16。感觉很对,结果系统测试TLE。。T.T。。出题人太坑爹,case数也需要算到复杂度里。。
做法三:
可以感觉到上面的做法都不太优。
放弃统计F(x) = [0..15]的数分别有多少个。直接算[0, A]的F(x)的和。
dp[len][pre]表示[0, 10^len)的数,之前高位异或和为pre,最后对答案的贡献的和。时间复杂度O(10^5*9),算上25组case也没有问题。。
然后发现这题的数据有前缀0,可能有人会因为这个导致错,提醒一下。。
代码
/************************************************************************* > File Name: d.cpp > Author: james47 > Mail: > Created Time: Sat Sep 12 20:15:56 2015 ************************************************************************/ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int maxn = 101000; const int mod = 1e9+7; int d[maxn]; char sa[maxn], sb[maxn]; int dp[maxn][16]; int dfs(int pos, int pre, bool bound){ if (pos == 0){ return pre; } if (!bound && dp[pos][pre] != -1) return dp[pos][pre]; int ret = 0; int lim = bound? d[pos]: 9; for (int i = 0; i <= lim; i++){ int tmp = dfs(pos-1, pre^i, bound&&i==lim); ret += tmp; if (ret >= mod) ret -= mod; } if (!bound){ dp[pos][pre] = ret; } return ret; } int solve(char* s){ int p = 0; while(s[p] == '0') p++; int len = strlen(s); if (p == len) return 0; int i, j; for (i = len-1, j = 1; i >= p; i--, j++) d[j] = s[i] - '0'; j--; return dfs(j, 0, true); } int cal(char *s){ int len = strlen(s); int ret = 0; for (int i = 0; i < len; i++) ret ^= s[i] - '0'; return ret; } int T; int main() { memset(dp, -1, sizeof(dp)); scanf("%d", &T); int cas = 0; while(T--){ scanf("%s %s", sa, sb); printf("Case #%d: ", ++cas); int res = (solve(sb) - solve(sa) + cal(sa) + mod) % mod; printf("%d\n", res); } return 0; }
E
Source
hdu 5436题意
一棵树,点有权值,叶子和根连通。每次询问两个点u和v,问u到v的路径,路径上点权和最小,顺带求上面的最大点权。多个最小时,让路径上最大点权最大。分析
可以直接看官方题解。。最基本的路径就是走到lca,没有修改啥的,可以倍增。。
然后可能是u走到叶子,然后从根走到v。
还有一种容易被忘记。。u走到叶子到根,再到另一个叶子,通过这个叶子到v。。
所以我们先dfs一遍,求出每个点到根的距离和,路径上最大点权等等,并求出到子树哪个叶子最近,第二次dfs要用。
然后还得再dfs一遍,求每个点离哪个叶子最近,简单的树形dp。
也可以直接用Dijkstra。。
代码很丑。。不推荐看。。
代码
/************************************************************************* > File Name: hdu_5436.cpp > Author: james47 > Mail: > Created Time: Fri Sep 18 20:49:53 2015 ************************************************************************/ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const int maxn = 51000; const int inf = 2e9; struct node{ int w, fa, dep, s0, ma0, s1, ma1; } a[maxn]; struct edge{ int v, n; }; int n, q; inline void chkmax(int& a, int b){ if (b > a) a = b; } int o[maxn][17]; int p[maxn][17]; void work(){ for (int i = 0; i <= n; i++){ p[i][0] = a[i].fa; o[i][0] = a[a[i].fa].w; } //突然发现这里写反了。。不过刚好这题不会影响。。 //u的祖先标号都比它小。。 for (int i = 1; i <= n; i++) for (int j = 1; j <= 16; j++){ p[i][j] = p[p[i][j-1]][j-1]; o[i][j] = max(o[i][j-1], o[p[i][j-1]][j-1]); } } int esize; int en[maxn]; edge e[maxn*2]; void addedge(int u, int v){ e[esize].v = v; e[esize].n = en[u]; en[u] = esize ++; } void dfs0(int u){ a[u].dep = a[a[u].fa].dep + 1; a[u].s0 = inf, a[u].ma0 = 0; a[u].s1 = a[a[u].fa].s1 + a[u].w; a[u].ma1 = max(a[u].w, a[a[u].fa].ma1); for (int t = en[u]; t != -1; t = e[t].n){ int v = e[t].v; dfs0(v); if (a[v].s0 < a[u].s0 || (a[v].s0 == a[u].s0 && a[u].ma0 < a[v].ma0)){ a[u].s0 = a[v].s0; a[u].ma0 = a[v].ma0; } } if (a[u].s0 == inf) a[u].s0 = 0; a[u].s0 += a[u].w; chkmax(a[u].ma0, a[u].w); } void dfs1(int u){ int s0, ma0; for (int t = en[u]; t != -1; t = e[t].n){ int v = e[t].v; s0 = a[u].s0 + a[v].w; ma0 = max(a[u].ma0, a[v].w); if (s0 < a[v].s0 || (s0 == a[v].s0 && ma0 > a[v].ma0)){ a[v].s0 = s0; a[v].ma0 = ma0; } dfs1(v); } } inline void update(int &a, int &b, int c, int d){ // printf("%d %d\n", c, d); if (a > c || (a == c && b < d)) a = c, b = d; } int cal(int x, int y, int& t){ t = max(a[x].w, a[y].w); if (a[x].dep < a[y].dep) swap(x, y); for (int i = 16; i >= 0; i--){ if (a[x].dep - (1<<i) >= a[y].dep){ chkmax(t, o[x][i]); x = p[x][i]; } } if (x == y) return x; for (int i = 16; i >= 0; i--){ if (a[x].dep - (1<<i) >= 0 && p[x][i] != p[y][i]){ chkmax(t, o[x][i]); chkmax(t, o[y][i]); x = p[x][i]; y = p[y][i]; } } chkmax(t, a[a[x].fa].w); return a[x].fa; } int T; int main() { a[0].dep = -1; a[0].fa = 0; a[0].w = 0; a[0].s0 = a[0].s1 = a[0].ma1 = 0; scanf("%d", &T); while(T--){ scanf("%d %d", &n, &q); a[1].fa = 0; esize = 0; memset(en, -1, sizeof(int)*(n+1)); for (int i = 2; i <= n; i++){ scanf("%d", &a[i].fa); addedge(a[i].fa, i); // addedge(i, a[i].fa); } for (int i = 1; i <= n; i++){ scanf("%d", &a[i].w); } work(); dfs0(1); dfs1(1); // for (int i = 1; i <= n; i++) // printf("%d %d %d %d\n", a[i].s0, a[i].ma0, a[i].s1, a[i].ma1); while(q--){ int u, v; scanf("%d %d", &u, &v); int t0, t1, lca; lca = cal(u, v, t1); t0 = a[u].s1 + a[v].s1 - a[lca].s1 * 2 + a[lca].w; // printf("%d %d %d\n", lca, t0, t1); update(t0, t1, a[u].s0 + a[v].s0 + a[1].w, max(a[1].w, max(a[u].ma0, a[v].ma0))); update(t0, t1, a[u].s0 + a[v].s1, max(a[u].ma0, a[v].ma1)); update(t0, t1, a[u].s1 + a[v].s0, max(a[u].ma1, a[v].ma0)); printf("%d %d\n", t0, t1); } } return 0; }
相关文章推荐
- 类中的const成员函数
- Servlet---JavaWeb技术的核心基础,JavaWeb框架的基石(一)
- 减少C盘空间占用的技巧
- Oracle 11g RAC开启归档,闪回并设置各自不同的路径
- 第七课 光照和键盘控制
- 关于如何使用thinkphp自带的分页功能
- 第五章 RARP:逆地址解析协议
- 零基础学python-16.6 嵌套作用域
- 零基础学python-16.6 嵌套作用域
- 第六课纹理映射:
- Extended Vertical Label Control in C# .NET
- 二维数组排序
- Mybatis学习之入门
- 字典树:求以某字符串开始的单词个数
- android之Service之Binder学习
- vector的使用方法
- esri开发大赛项目总结
- Javaweb的基础
- android:open failed: EISDIR (Is a directory)
- Java中的Enum的使用与分析