[关闭]
@sensitive-cs 2019-02-13T14:07:19.000000Z 字数 3381 阅读 597

G - Quadcopter Competition

题意:

求从一个点出发,绕着一根旗走,然后回到原点形成一个闭合的回路所需要的最少步数。

思路:

找出出发点到棋子周围8个点的最小距离s,答案是s * 2 + 8。

代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <algorithm>
  4. #include <cmath>
  5. using namespace std;
  6. int main()
  7. {
  8. int a,b;
  9. int x,y;
  10. scanf("%d%d",&a,&b);
  11. scanf("%d%d",&x,&y);
  12. int ans = 1000;
  13. for (int i = -1;i <= 1;i++)
  14. {
  15. for (int j = -1;j <= 1;j++)
  16. {
  17. if (i == 0 && j == 0) continue;
  18. int tmp = 0;
  19. tmp += (fabs(a-(x+i)) + fabs(b-(y+j)));
  20. ans = min(ans,tmp);
  21. }
  22. }
  23. printf("%d\n",ans * 2 + 8);
  24. return 0;
  25. }

H - Kayaking

题意:

有n条船,其中2条船是单人船,其余的船是双人船。单人船的不稳定性恒为0;双人船的不稳定性为坐在船上的人的体重之差的绝对值。有2 * n个人,要安排全部的人坐到船上,并且使得所有船的不稳定性之和最小。输出这个最小值。

思路:

由于n比较小,所以枚举两个人坐单人船,剩下的人体重排序,一定是体重相邻的人坐一起。

代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <algorithm>
  4. #include <map>
  5. using namespace std;
  6. int a[105];
  7. map<int,int> mp;
  8. int main()
  9. {
  10. int n;
  11. scanf("%d",&n);
  12. n *= 2;
  13. int ans = 1000000;
  14. for (int i = 1;i <= n;i++) scanf("%d",&a[i]);
  15. for (int i = 1;i <= n;i++) mp[a[i]]++;
  16. for (int i = 1;i <= n;i++)
  17. {
  18. for (int j = i + 1;j <= n;j++)
  19. {
  20. int b[105];
  21. int num = 0;
  22. mp[a[i]]--;
  23. mp[a[j]]--;
  24. for (auto it = mp.begin();it != mp.end();++it)
  25. {
  26. int v = it -> first;
  27. int cnt = it -> second;
  28. while (cnt)
  29. {
  30. cnt--;
  31. b[++num] = v;
  32. }
  33. }
  34. sort(b+1,b+1+num);
  35. int tmp = 0;
  36. for (int i = 1;i <= num;i += 2)
  37. {
  38. tmp += b[i+1] - b[i];
  39. }
  40. ans = min(ans,tmp);
  41. mp[a[i]]++;
  42. mp[a[j]]++;
  43. }
  44. }
  45. printf("%d\n",ans);
  46. return 0;
  47. }

I - Jury Meeting

题意:

有n+1座城市,下标0-n。其中1-n每座城市都有一位委员。他们现在要一起集中到城市0,持续k天,然后再飞回各自的城市。有若干航班,每个航班要么是到0,要么是从0出发到其他城市,并且每个航班都是当天出发当天到达。每个航班有一定的花费。现在要求能够让他们在0集中k天,最后回到自己的城市的最小花费。到达或者回去的当天不算在k天之中。

思路:

这个题目是这个专题当中最难的题目(当之无愧。

首先很明显的想法是可以求出每一天全部人都到0城市的最小花费,不满足就赋值为INF;同样,可以计算出每一天所有人都返回到所在城市的最小花费,不满足也赋值为INF。

现在就是要求出某一天当所有人都到达0后,假设这一天为x,总花费为a,在x + 1 + k及其之后的所有天当中,回去的花费最小的,假设为b,那么就是求a + b的最小值。

朴素的想法是枚举,但是时间复杂度肯定爆炸。那么想一想优化,嗯,可以用线段树(但是我不会啊

其实还有一种很显然的想法,如果第一天所有人都到了,花费为x,那么第二天肯定是满足所有人都到了的条件,假设第二天花费为y(可以与x不同,想一想,为什么?),那么前两天所有人都到的花费肯定是,同理前三天所有人的花费就是min(前两天所有人的最小花费,第三天的花费)。所以用前缀和维护即可。前缀和是什么?(我也不知道

代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <algorithm>
  4. #include <vector>
  5. using namespace std;
  6. typedef long long ll;
  7. const int N = 1e6 + 10;
  8. const ll inf = 1e16;
  9. struct node
  10. {
  11. int loc,cost;
  12. node(){};
  13. node(int x,int y)
  14. {
  15. loc = x;
  16. cost = y;
  17. }
  18. };
  19. int a[N],b[N];
  20. ll sa[N],sb[N];
  21. ll pre[N],sub[N];
  22. vector<node> st[N];
  23. vector<node> en[N];
  24. int main()
  25. {
  26. int n,m,k;
  27. scanf("%d%d%d",&n,&m,&k);
  28. int mx = 0;
  29. for (int i = 0;i < m;i++)
  30. {
  31. int d;
  32. int de,ar;
  33. int c;
  34. scanf("%d%d%d%d",&d,&de,&ar,&c);
  35. mx = max(d,mx);
  36. if (de == 0)
  37. {
  38. en[d].push_back(node(ar,c));
  39. }
  40. else
  41. {
  42. st[d].push_back(node(de,c));
  43. }
  44. }
  45. int cnt = 0;
  46. ll sum = 0;
  47. for (int i = 1;i <= mx;i++)
  48. {
  49. for (auto x : st[i])
  50. {
  51. int loc = x.loc;
  52. int cost = x.cost;
  53. if (a[loc])
  54. {
  55. if (a[loc] > cost)
  56. {
  57. sum -= a[loc];
  58. sum += cost;
  59. a[loc] = cost;
  60. }
  61. }
  62. else
  63. {
  64. cnt++;
  65. a[loc] = cost;
  66. sum += a[loc];
  67. }
  68. }
  69. if (cnt >= n)
  70. {
  71. sa[i] = sum;
  72. }
  73. else
  74. {
  75. sa[i] = inf;
  76. }
  77. }
  78. sum = 0;
  79. cnt = 0;
  80. for (int i = mx;i >= 1;i--)
  81. {
  82. for (auto x : en[i])
  83. {
  84. int loc = x.loc;
  85. int cost = x.cost;
  86. if (b[loc])
  87. {
  88. if (b[loc] > cost)
  89. {
  90. sum -= b[loc];
  91. sum += (b[loc] = cost);
  92. }
  93. }
  94. else
  95. {
  96. cnt++;
  97. b[loc] = cost;
  98. sum += b[loc];
  99. }
  100. }
  101. if (cnt >= n)
  102. {
  103. sb[i] = sum;
  104. }
  105. else
  106. {
  107. sb[i] = inf;
  108. }
  109. }
  110. pre[0] = inf;
  111. for (int i = 1;i <= mx;i++)
  112. {
  113. pre[i] = min(pre[i-1],sa[i]);
  114. }
  115. sub[mx+1] = inf;
  116. for (int i = mx;i >= 1;i--)
  117. {
  118. sub[i] = min(sub[i+1],sb[i]);
  119. }
  120. ll ans = inf;
  121. for (int i = 1;i + k + 1 <= mx;i++)
  122. {
  123. ans = min(ans,pre[i] + sub[i+k+1]);
  124. }
  125. if (ans >= inf) return 0*puts("-1");
  126. printf("%lld\n",ans);
  127. return 0;
  128. }

J - Add All

题意:

求把n个数字相加的代价的总和的最小值。每两个数字相加的代价是两个数字的和。

思路:

优先队列,每次取出最小的两个数字相加即可。

代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <algorithm>
  4. #include <queue>
  5. using namespace std;
  6. typedef long long ll;
  7. priority_queue<ll,vector<ll>,greater<ll> > pq;
  8. int main()
  9. {
  10. int n;
  11. while (~scanf("%d",&n) && n)
  12. {
  13. while (!pq.empty()) pq.pop();
  14. ll ans = 0;
  15. for (int i = 0;i < n;i++)
  16. {
  17. int x;
  18. scanf("%d",&x);
  19. pq.push(x);
  20. }
  21. while (pq.size() > 1)
  22. {
  23. ll x = pq.top();
  24. pq.pop();
  25. ll y = pq.top();
  26. pq.pop();
  27. ans += x;
  28. ans += y;
  29. pq.push(x+y);
  30. }
  31. printf("%lld\n",ans);
  32. }
  33. return 0;
  34. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注