当前位置:   article > 正文

重庆交通大学程序设计竞赛集训队暑假第三次练习赛——题解_usaco 2015 january contest bronz

usaco 2015 january contest bronz

题目来源及知识点

A:(贪心)

B:《算法竞赛进阶指南》-0x54.例题.没有上司的舞会(树形DP)

C:USACO 2015 January Contest Bronze-A.Cow Routing(模拟)

D:LeetCode.2327-知道秘密人数前缀和、DP)

E:CodeForce Round #806(Div.4)-B.ICPC Balloons(模拟)

(由于C、E两题较简单所以就没有写解析,代码必要地方有注释)

Problem.A 打包烧饼

本题使用的就是贪心,先用c[i]减去r[i],得到每个餐盒里还需要的烧饼的数量,然后将其从小到大排序,优先往需求小的餐盒里放,这样能保证最后能被放满的餐盒数量最多

  1. #pragma GCC optimize(2)
  2. #include <bits/stdc++.h>
  3. using namespace std;
  4. #define endl '\n'
  5. #define int long long
  6. const int N = 50010;
  7. int n, m, r, c[N];
  8. void solve()
  9. {
  10. cin >> n >> m;
  11. for (int i = 1; i <= n; i++)
  12. {
  13. cin >> c[i];
  14. }
  15. for (int i = 1; i <= n; i++)
  16. {
  17. cin >> r;
  18. c[i] -= r;
  19. }
  20. sort(c + 1, c + 1 + n);
  21. int ans = 0;
  22. for (int i = 1; i <= n; i++)
  23. {
  24. if (m < c[i])
  25. break;
  26. ans++;
  27. m -= c[i];
  28. }
  29. cout << ans << endl;
  30. }
  31. signed main()
  32. {
  33. ios::sync_with_stdio(false);
  34. cin.tie(0); cout.tie(0);
  35. solve();
  36. return 0;
  37. }

Problem.B 开黑之夜

本题很容易知道这个关系结构是个树形结构,每个人的happy值都作为节点的权值。要求解的是最优子结构,那么这就是个树形DP的问题。

dp[i][0]表示在以i为子树的员工中选择一些人参加活动且不包括i时的总happy值,dp[i][1]表示以i为子树的员工中选择一些人参加活动且包括i时的happy值。 

当第i个人不参加活动时,它的直接下属(子节点)可以参加,也可以不参加,即状态转移方程为

dp[i][0]=\sum_{s\in Son(i)}^{}max(dp[s][0],dp[s][1])

Son(i)表示i的子节点的集合,下同)

当第i个人参加活动时,它的直接下属(字节点)一定不参加活动,即状态转移方程为

dp[i][1]=a[i]+\sum_{s\in Son(i)}^{}dp[s][0]

 表示第i个人的happy值

则我们需要找到的是以老板作为根节点时的最大值,假设老板节点为boss,即要求解max(dp[boss][0],dp[boss][1]),那么本题就可以以DFS的方式来求出每个子树的最大happy值依次向上传递。

  1. #pragma GCC optimize(2)
  2. #include <bits/stdc++.h>
  3. using namespace std;
  4. #define endl '\n'
  5. #define int long long
  6. const int N = 6010, M = 12010;
  7. int n, a[N]; //a[]:happy值
  8. int h[N], e[M], ne[M], idx; //邻接表存储树
  9. int dp[N][2];
  10. bool st[N]; //该节点是否有父节点
  11. void init()
  12. {
  13. memset(h, -1, sizeof(h));
  14. idx = 0;
  15. }
  16. //连接一条从p到s的边,p是s的直接上级
  17. void add(int p, int s)
  18. {
  19. e[idx] = s;
  20. ne[idx] = h[p];
  21. h[p] = idx++;
  22. }
  23. void dfs(int u)
  24. {
  25. dp[u][1] = a[u];
  26. for (int i = h[u]; i != -1; i = ne[i])
  27. {
  28. int j = e[i];
  29. dfs(j);
  30. dp[u][0] += max(dp[j][0], dp[j][1]);
  31. dp[u][1] += dp[j][0];
  32. }
  33. }
  34. void solve()
  35. {
  36. init();
  37. cin >> n;
  38. for (int i = 1; i <= n; i++)
  39. {
  40. cin >> a[i];
  41. }
  42. int s, p;
  43. for (int i = 1; i < n; i++)
  44. {
  45. cin >> s >> p;
  46. add(p, s);
  47. st[s] = true;
  48. }
  49. int boss= 1;
  50. //没有父节点的点就是老板
  51. while (st[boss])
  52. {
  53. boss++;
  54. }
  55. dfs(boss);
  56. cout << max(dp[boss][0], dp[boss][1]) << endl;
  57. }
  58. signed main()
  59. {
  60. ios::sync_with_stdio(false);
  61. cin.tie(0); cout.tie(0);
  62. solve();
  63. return 0;
  64. }

Problem.C 旅游线路

  1. #pragma GCC optimize(2)
  2. #include <bits/stdc++.h>
  3. using namespace std;
  4. #define endl '\n'
  5. #define int long long
  6. int a, b, n;
  7. void solve()
  8. {
  9. cin >> a >> b >> n;
  10. int ans = 1010;
  11. while (n--)
  12. {
  13. int sum, m, pos;
  14. cin >> sum >> m;
  15. bool flag = false;
  16. while (m--)
  17. {
  18. cin >> pos;
  19. if (pos == a) //找到了出发起点
  20. flag = true;
  21. if (pos == b && flag) //找到了终点
  22. ans = min(ans , sum);
  23. }
  24. }
  25. if (ans == 1010)
  26. cout << -1 << endl;
  27. else
  28. cout << ans <<endl;
  29. }
  30. signed main()
  31. {
  32. ios::sync_with_stdio(false);
  33. cin.tie(0); cout.tie(0);
  34. solve();
  35. return 0;
  36. }

Problem.D 十七的秘密

本题也是采用动态规划,f[i]表示第i天新增知道秘密的人数,初始时f[1]=1,其余为0。对于f[i],新增的人数为区间[i-d2+d1,i-d1]内知道秘密的人数之和,那么最终答案就是区间[n-d2+d1,n]内知道秘密的人数之和。

根据以上分析实际上我们可以采用前缀和来求区间和,因此dp[i]表示第1天到第i天新增的知道秘密的人的前缀和,则状态转移方程为

dp[i]=dp[i-1]+dp[i-d1]-dp[i-d2]

那么最终第n天知道还秘密的人数就是dp[n]-dp[n-d2],要注意的是i-d1i-d2不能为负。

  1. #pragma GCC optimize(2)
  2. #include <bits/stdc++.h>
  3. using namespace std;
  4. #define endl '\n'
  5. #define int long long
  6. const int N = 1010, mod = 1e9 + 7;
  7. int n, d1, d2, dp[N];
  8. void solve()
  9. {
  10. cin >> n >> d1 >> d2;
  11. dp[0] = 0, dp[1] = 1;
  12. for (int i = 2; i <= n; i++)
  13. {
  14. dp[i] = dp[i - 1];
  15. if (i >= d1)
  16. dp[i] = (dp[i] + dp[i - d1]) % mod;
  17. if (i >= d2)
  18. dp[i] = (dp[i] - dp[i - d2]) % mod;
  19. }
  20. cout << ((dp[n] - dp[n - d2]) % mod + mod) % mod << endl;
  21. }
  22. signed main()
  23. {
  24. ios::sync_with_stdio(false);
  25. cin.tie(0); cout.tie(0);
  26. solve();
  27. return 0;
  28. }

Problem.E ICPC的气球

  1. #pragma GCC optimize(2)
  2. #include <bits/stdc++.h>
  3. using namespace std;
  4. #define endl '\n'
  5. #define int long long
  6. map<char,int> ball;
  7. int t, n;
  8. string s;
  9. void solve()
  10. {
  11. cin >> s;
  12. int ans = 0;
  13. for (auto c: s)
  14. {
  15. if (ball[c] == 0) //如果该字母第一次出现
  16. ans+=2; //加两个气球
  17. else
  18. ans++;
  19. ball[c]++; //存入map
  20. }
  21. cout << ans << endl;
  22. ball.clear(); //处理完一组数据清空map
  23. }
  24. signed main()
  25. {
  26. ios::sync_with_stdio(false);
  27. cin.tie(0); cout.tie(0);
  28. cin >> t;
  29. while (t--)
  30. {
  31. solve();
  32. }
  33. return 0;
  34. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/1003979
推荐阅读
  

闽ICP备14008679号