[关闭]
@2368860385 2020-11-07T03:04:20.000000Z 字数 2901 阅读 201

day4

正睿青岛


T1

给你一个序列a1,a2,…,an,我们称一个区间[l,r]为好的区间当且仅当al,al+1,…,ar这些数字最大值不超过最小值的k倍。
现在给你一个序列,问有多少个太阳区间。
注意:此题空间限制为16MB。

每个点为右端点的时候,左端点与他形成的区间中,最大值会影响一段一段的区间。就是当一个oooxooooi当前在i,最大值x,那么左边所有的端点与i形成的区间最大值都是x,所以可以用两个单调栈来记录最大值区间,和最小值区间。
最大值是递减的,最小值最递增的,所以越往右,越满足条件(什么叫越满足条件:最小值越大,最大值越小,k*最小值越大于最大值),一定有一个位置右边满足条件,左边不满足了,于是可以二分。
其实,将单调栈,改成单调队列(双端队列)就行了。 首先这些二分到的位置一定是在单调栈里的位置,所以如果队首不满足条件,弹出队首,知道满足。每次位置不断往右移。

T3

分数规划,二分答案,a[i] b[i] -=ans
60分线段树优化建图网络流,最大独立集
正解dp
dp[i]表示考虑到右侧第i个,每次枚举上次选的点j < i,然后左侧的覆盖区间在j~i的点就可以被选了(加入独立集),预处理前缀和则左侧覆盖的区间在(j,i)间的有多少个n^2。复杂度O(n^2logn)
优化:
每次枚举右侧的点时,总是在前面找一个最小的j,满足dp[j]+cost(i,j)最小,f[j] = dp[j] + cost(i, j),所以就是max(f[i])。
更新f数组:每次计算完这个右端点后,将所有左侧区间为l~i的区间(就是以当前点为右端点的区间)的左侧点可以加入到1~l-1的f数组里。所以可以用线段树优化。
设f数组辅助,f[j]表示从i转移到当前点时,从j转移的代价。

  1. for(i=1;i<=n;i++)
  2. {
  3. dp[i]=max(f[1..n-1]); //线段树
  4. f[i]=dp[i]
  5. for 右端点为i的区间[l,r] w
  6. f[1...l-1]+=w //线段树
  7. }
  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<iostream>
  6. #include<cctype>
  7. #include<set>
  8. #include<vector>
  9. #include<queue>
  10. #include<map>
  11. #define fi(s) freopen(s,"r",stdin);
  12. #define fo(s) freopen(s,"w",stdout);
  13. using namespace std;
  14. typedef long long LL;
  15. typedef double LD;
  16. inline int read() {
  17. int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
  18. for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
  19. }
  20. const int N = 30005;
  21. const LD eps = 1e-8;
  22. const LD INF = 1e18;
  23. struct Node{
  24. int w, l, r;
  25. }A[N];
  26. int B[N], n, m, k;
  27. vector<int> vec[N];
  28. LD ta[N], tb[N], mx[N << 2], tag[N << 2];
  29. #define Root 0, m, 1
  30. #define lson l, mid, rt << 1
  31. #define rson mid + 1, r, rt << 1 | 1
  32. inline void pushup(int rt) {
  33. mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]);
  34. }
  35. inline void pushdown(int rt) {
  36. if (tag[rt] > -eps) {
  37. tag[rt << 1] += tag[rt], tag[rt << 1 | 1] += tag[rt];
  38. mx[rt << 1] += tag[rt], mx[rt << 1 | 1] += tag[rt];
  39. tag[rt] = 0;
  40. }
  41. }
  42. void build(int l,int r,int rt) {
  43. mx[rt] = tag[rt] = 0;
  44. if (l == r) return ;
  45. int mid = (l + r) >> 1;
  46. build(lson); build(rson);
  47. }
  48. void update(int l,int r,int rt,int L,int R,LD v) {
  49. if (L > R) return ;
  50. if (L <= l && r <= R) {
  51. tag[rt] += v; mx[rt] += v;
  52. return ;
  53. }
  54. pushdown(rt);
  55. int mid = (l + r) >> 1;
  56. if (L <= mid) update(lson, L, R, v);
  57. if (R > mid) update(rson, L, R, v);
  58. pushup(rt);
  59. }
  60. LD query(int l,int r,int rt,int L,int R) {
  61. if (L > R) return 0;
  62. if (L <= l && r <= R) {
  63. return mx[rt];
  64. }
  65. int mid = (l + r) >> 1;
  66. LD res = -INF;
  67. if (L <= mid) res = max(res, query(lson, L, R));
  68. if (R > mid) res = max(res, query(rson, L, R));
  69. return res;
  70. }
  71. bool check(LD x) {
  72. LD ans = 0, sum = 0;
  73. for (int i=1; i<=n; ++i) ta[i] = max((LD)0, x - A[i].w), sum += A[i].w - x;
  74. for (int i=1; i<=m; ++i) tb[i] = max((LD)0, x - B[i]), sum += B[i] - x;
  75. build(Root);
  76. for (int i=1; i<=m+1; ++i) {
  77. ans = query(Root, 0, i - 1) + tb[i];
  78. for (int sz=vec[i].size(),j=0; j<sz; ++j) update(Root, 0, A[vec[i][j]].l - 1, ta[vec[i][j]]);
  79. update(Root, i, i, ans);
  80. }
  81. return sum + ans > -eps;
  82. }
  83. int main() {
  84. n = read(), m = read(), k = read();
  85. LD L = INF, R = -INF, ans;
  86. for (int i=1; i<=n; ++i) A[i].w = read(), L = min((LD)A[i].w, L);
  87. for (int i=1; i<=m; ++i) B[i] = read(), R = max((LD)B[i], R);
  88. for (int i=1; i<=n; ++i) {
  89. A[i].l = read(), A[i].r = read();
  90. vec[A[i].r].push_back(i);
  91. }
  92. while (R - L > eps) {
  93. LD mid = (L + R) / 2.0;
  94. if (check(mid)) ans = mid, L = mid;
  95. else R = mid;
  96. }
  97. double pr = ans;
  98. printf("%.10lf",pr);
  99. return 0;
  100. }

装箱问题

很多个ai,∑ai<=n,问哪些数可以表示出。
将很多个ai合并。
2x+1个a => a, x个2a
2x+2个a => a, a, x个2a。
O(sqrt(n) / 32)

从头开始不断合并。

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