[关闭]
@dxbdly 2021-02-08T11:15:03.000000Z 字数 3276 阅读 178

C2020 2021.1.24模拟赛

信息学——模拟赛


T1 Unlock

考场题面有锅,然而最后出题人也没补好,所以这题就咕咕了吧。

T2 Shelf

分析

考虑DP。

设:表示前 本书的最小值。

枚举点 ,表示 为最后一层。

则有方程:

一个技巧: 开始倒着枚举,好处是我们可以一遍扫一遍存下 非常方便

(当然用ST表和前缀和维护也可以)

  1. //The code is from dawn_sdy
  2. #include<bits/stdc++.h>
  3. #define INF INT_MAX
  4. using namespace std;
  5. inline int read() {
  6. int x = 0;
  7. char c = getchar();
  8. bool f = 0;
  9. while(!isdigit(c)) f |= (c == '-'), c = getchar();
  10. while(isdigit(c)) x = (x * 10) + (c ^ 48), c = getchar();
  11. return f ? -x : x;
  12. }
  13. const int maxn = 2005;
  14. int n, l;
  15. struct node {
  16. int h, w;
  17. }book[maxn];
  18. int f[maxn], maxx, sum;
  19. int main(){
  20. // freopen("bookshelf.in", "r", stdin);
  21. // freopen("bookshelf.out", "w", stdout);
  22. n = read(), l = read();
  23. for(register int i = 1; i <= n; ++i) book[i].h = read(), book[i].w = read();
  24. for(register int i = 1; i <= n; ++i) {
  25. f[i] = INF, maxx = sum = 0;
  26. for(register int j = i; j >= 1; --j) {
  27. maxx = max(maxx, book[j].h), sum += book[j].w;
  28. if(sum > l) break;
  29. f[i] = min(f[i], f[j - 1] + maxx);
  30. }
  31. }
  32. printf("%d", f[n]);
  33. return 0;
  34. }

T3 running

分析

先吐槽一句:题面依旧有问题,最后是理解std改的题面。。。

不过此题思路极其巧妙,值得一做。

首先考虑一定只存在速度快的奶牛追上速度慢的奶牛,那么如果按照速度排序,奶牛 的贡献只与有关

考虑奶牛 追上奶牛 的贡献:

首先算出时间


表示出 的路程差:

算出贡献:

化简一下:

的答案为:

在考虑这个式子怎么优化前,我们先来考虑一个事情:

之间的关系。

设: 其中 为整数部分, 为小数部分。

我们考虑的影响


​ 那么我们可以考虑只考虑的情况,最后算一遍的情况有多少种,减去即可。

那么就可以将上式展开:


其中第一项是常量,复杂度,第二项求和可以用前缀和处理,复杂度,那么我们要计算的就是的个数。

考虑到小数部分不好处理,我们将小数转换成余数,记余数为

则可以发现 就是 满足 的个数,即可以看成 数组逆序对的对数,而逆序对采用树状数组维护即可,复杂度

  1. //The code is from dawn_sdy
  2. #include<bits/stdc++.h>
  3. #define int long long
  4. using namespace std;
  5. inline int read() {
  6. int x = 0;
  7. char c = getchar();
  8. bool f = 0;
  9. while(!isdigit(c)) f |= (c == '-'), c = getchar();
  10. while(isdigit(c)) x = (x * 10) + (c ^ 48), c = getchar();
  11. return f ? -x : x;
  12. }
  13. const int maxn = 1e5 + 5, maxl = 1e6;
  14. int n, le, c, ans, sum, maxx;
  15. struct node {
  16. int x, y, v;
  17. }point[maxn];
  18. inline bool operator <(node a, node b) {
  19. return a.x != b.x ? a.x < b.x : a.y < b.y;
  20. }
  21. namespace Binary_Index_Tree {
  22. int Tree[maxl << 1 + 5];
  23. inline int lowbit(int x) { return x & (-x); }
  24. inline void Update(int x, int num) {
  25. while(x <= maxl) { Tree[x] += num, x += lowbit(x); }
  26. }
  27. inline int Query(int x) {
  28. int res = 0;
  29. while(x) { res += Tree[x], x -= lowbit(x); }
  30. return res;
  31. }
  32. }
  33. using namespace Binary_Index_Tree;
  34. signed main() {
  35. n = read(), le = read(), c = read();
  36. for(register int i = 1; i <= n; ++i) point[i].v = read(), maxx = max(maxx, point[i].v);
  37. for(register int i = 1; i <= n; ++i) point[i].x = point[i].v * le / maxx, point[i].y = (point[i].v * le) % maxx;
  38. sort(point + 1, point + n + 1);
  39. for(register int i = 1; i <= n; ++i) {
  40. ans += point[i].x * (i - 1) - sum - (Query(maxl) - Query(point[i].y)), sum += point[i].x;
  41. if(point[i].y) Update(point[i].y, 1);
  42. }
  43. printf("%lld", ans);
  44. return 0;
  45. }

反思与总结

一道非常好的题,需要记住的是 的转化方式,以及将小数部分对应余数,进而转化为逆序对的思想。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注