Codeforces Round #436 (Div. 2)E,F详解
2017-09-27 00:08
357 查看
鉴于太多人把D做出来了,实际上D就是道模拟简单题,所以本篇博客并没有D的题解。如果有需要的读者可以联系博主,博主会很热心的为你解释的(笑)。。
E题题解:Polycarp家着火了。。他家里有n个值钱的东西,每一个东西有一个营救需要的时间和一个烧毁需要的时间。问Polycarp能救出的东西的最大价值为多少,并输出营救顺序。
思路:裸的01背包问题。。如果不明白01背包问题可以看看紫书的动规专题。
思路出来了,博主觉得有必要讲的两点就是,一,它和01背包问题唯一不同的是有一个限制时间,不像01背包啥时候都可以拿,它拿某个物品的时间是一段区间。二,能拿某个物品的时间怎么算,首先状态转移方程式为
dp[T]=max(dp[T],dp[T-t[i]]+w[i]),显然T< d[i],并且T>t[i].所以只会更新该区间的值,但更新完了肯定会影响后面的T(从这个式子就可以看出),所以为了复杂度低(你也可以更新后面的T,加个判断即可),首先把物品按照d排个序,先取小的,再取大的,这样就可保证再更新大的时候小的已经全部被更新了。
代码如下:
F题题意:给你一个图,有q次询问,从s到t的结点最小字典序路径中的第k个结点是谁。
思路:这题好啊,让博主学习到了图上的倍增。另外也让博主领悟到了一个小套路,即如果题目给你一个k,让你求路径上的第k个点,这大概就需要用倍增的思想了。
思路挺简单的,那么如何用倍增呢?请读者仔细看代码,并理解从中倍增的奥妙和如何用倍增判断是环的。
代码浑然天成啊。。。博主想解释为啥用离线,但感觉没必要,因为都这样写了,还能用在线不成。希望读者仔细阅读代码,学会了又有新姿势上分了~
E题题解:Polycarp家着火了。。他家里有n个值钱的东西,每一个东西有一个营救需要的时间和一个烧毁需要的时间。问Polycarp能救出的东西的最大价值为多少,并输出营救顺序。
思路:裸的01背包问题。。如果不明白01背包问题可以看看紫书的动规专题。
思路出来了,博主觉得有必要讲的两点就是,一,它和01背包问题唯一不同的是有一个限制时间,不像01背包啥时候都可以拿,它拿某个物品的时间是一段区间。二,能拿某个物品的时间怎么算,首先状态转移方程式为
dp[T]=max(dp[T],dp[T-t[i]]+w[i]),显然T< d[i],并且T>t[i].所以只会更新该区间的值,但更新完了肯定会影响后面的T(从这个式子就可以看出),所以为了复杂度低(你也可以更新后面的T,加个判断即可),首先把物品按照d排个序,先取小的,再取大的,这样就可保证再更新大的时候小的已经全部被更新了。
代码如下:
#include<iostream> #include<vector> #include<algorithm> using namespace std; struct node { int t, d, p; int idx; bool operator<(const node &b)const { return d < b.d; } }nodes[205]; vector<int>V[2005]; int dp[2005]; int main() { int n; cin >> n; for (int i = 1;i <= n;i++) { scanf("%d%d%d", &nodes[i].t, &nodes[i].d, &nodes[i].p); nodes[i].idx = i; } sort(nodes + 1, nodes + 1 + n); for(int i=1;i<=n;i++) for (int j = nodes[i].d - 1;j >= nodes[i].t;j--) { if (dp[j] < dp[j - nodes[i].t] + nodes[i].p) { dp[j] = dp[j - nodes[i].t] + nodes[i].p; V[j] = V[j - nodes[i].t]; V[j].push_back(nodes[i].idx); } } int theans = 0; int idx=-1; for(int i=0;i<=2000;i++) if (theans < dp[i]) { theans = dp[i]; idx = i; } cout << theans << endl; if (idx == -1) { cout << 0 << endl; return 0; } int Size = V[idx].size(); cout << Size << endl; for (int i = 0;i < Size;i++) { if (i != 0)printf(" "); printf("%d", V[idx][i]); } return 0; }
F题题意:给你一个图,有q次询问,从s到t的结点最小字典序路径中的第k个结点是谁。
思路:这题好啊,让博主学习到了图上的倍增。另外也让博主领悟到了一个小套路,即如果题目给你一个k,让你求路径上的第k个点,这大概就需要用倍增的思想了。
思路挺简单的,那么如何用倍增呢?请读者仔细看代码,并理解从中倍增的奥妙和如何用倍增判断是环的。
#include<iostream> #include<vector> #include<algorithm> #include<cstring> using namespace std; const int maxn = 3005; const int maxq = 4e5 + 10; vector<int>G[maxn], TO[maxn]; vector < pair<pair<int, int>, int>>Q[maxq]; bool vis[maxn]; #define MP(x,y) make_pair(x,y) void dfs(int node) { if (vis[node])return; vis[node] = 1; for (int i : TO[node]) dfs(i); } int st[maxn][13]; int ans[maxq]; int main() { int n, m, q; cin >> n >> m >> q; int u, v; for (int i = 1;i <= m;i++) { scanf("%d%d", &u, &v); G[u].push_back(v); TO[v].push_back(u); } int s, t, k; for (int i = 1;i <= q;i++) { scanf("%d%d%d", &s, &t, &k); Q[t].push_back(MP(MP(s, k), i)); } for (int i = 1;i <= n;i++)sort(G[i].begin(), G[i].end()); for (int i = 1;i <= n;i++)if(Q[i].size()) { memset(vis, 0, sizeof(vis)); dfs(i); memset(st, 0, sizeof(st)); for (int j = 0;j < 13;j++)st[n + 1][j] = n + 1; for (int j = 1;j <= n;j++) { if (j == i)st[j][0] = n + 1; else if (vis[j]) { for (int v : G[j]) { if (!vis[v])continue; st[j][0] = v; break; } } } for (int j = 1;j < 13;j++) for (int u = 1;u <= n;u++)if(vis[u]) st[u][j] = st[st[u][j - 1]][j - 1]; for (auto it : Q[i]) { int s = it.first.first; int k = it.first.second - 1; int id = it.second; if (vis[s]) { if (st[s][12] == n + 1) { for (int j = 0;j < 13;j++) if (k&(1 << j)) s = st[s][j]; if (s != n + 1) ans[id] = s; else ans[id] = -1; } else ans[id] = -1; } else { ans[id] = -1; } } } for (int i = 1;i <= q;i++) cout << ans[i] << endl; return 0; }
代码浑然天成啊。。。博主想解释为啥用离线,但感觉没必要,因为都这样写了,还能用在线不成。希望读者仔细阅读代码,学会了又有新姿势上分了~
相关文章推荐
- Codeforces Round #436 (Div. 2)
- Codeforces Round #436 (Div. 2)E.Fire
- Codeforces Round #436 (Div. 2) C. Bus
- Codeforces Round #436 (Div. 2)E. Fire
- Codeforces Round #436 (Div. 2)
- Codeforces Round #436 (Div. 2) C. Bus
- Codeforces Round #436 (Div. 2) C. Bus 来回路程问题
- Codeforces Round #436 (Div. 2) E. Fire(背包DP+输出路径)
- Codeforces Round #436 (Div. 2) 做题总结
- Codeforces Round #436 (Div. 2) C. Bus
- codeforces Round # 236(DIV 2)B. Trees in a Row
- Codeforces Round #172 (Div. 2) B. Nearest Fraction
- 【Codeforces Round 330 (Div 2)C】【博弈 贪心 脑洞】n个数AB轮流选到只剩俩,A希望差小B希望差大问最后差值
- Codeforces Round #243 (Div. 2)
- 【Codeforces Round 330 (Div 2)D】【计算几何 二分答案】Max and Bike 最小骑车距离使得圆上传感器很坐标位移为dis
- Codeforces Round 264(div2) C. Gargari and Bishops
- 【Codeforces Round 331 (Div 2)A】【水题】Wilbur and Swimming Pool 给出矩形1~4个顶点让你还原矩形
- Educational Codeforces Round 38 (Rated for Div. 2)A. Word Correction
- Codeforces Round #313 (Div. 2) 560C Gerald's Hexagon(脑洞)
- Codeforces Round #459 (Div. 2) C-The Monster (贪心)