ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

NOIP模拟55

2021-09-18 07:33:56  阅读:161  来源: 互联网

标签:return NOIP 55 mid 队列 inline 维护 模拟 define


T1:

  与模拟54T4较为相像,然而需要注意的点有所不同

首先比较显然的是DP方程:fi = fj + ai - (i - j) * (i - j - 1) / 2

常规思路为直接使用权值数据结构进行维护,然而无法处理后面的部分

考场上想过分块线段树树状数组,然而都失败了,于是突然发现对于 一点i

若i的可选部分中j为max,那么j之后的部分一定不会在成为max,于是考虑采用链表

通过截断链表的方式排除较劣值(仍然未想到斜率优化单调栈),然而发现问题一在于如何寻找前驱后继

我采用multiset维护,然而问题二在于前驱后继在本题中并不唯一,甚至可能形成环状结构,于是思路结束

通过昨天T1,我考虑能否降低维护的准确度以此换来信息的灵活性,然而仍然无法维护

  事实上正解的思路并不是单纯的数据结构维护信息,而是决策单调性

类似模拟54T4,考虑在计算fi时j比k更优的情况(仍然套路的直接解不等式)化简得到:

设gi = fi - i * (i - 1) / 2

  i > -(gj - gk) / (j - k)(i为常量,其余为变量)

根据>可以得出应维护右下凸包,同时递增

于是类似昨天T4的思路采取CDQ分治,利用左侧更新右侧

考虑首先消去a这一维,直接按a排序即可,接着在分治过程中按下标排序即可

注意点:首先模拟54未说的

单调队列的维护过程中,需要保证head >= tail,因为当队列中之存在一个点时,实际上还存在这原点,

这两个点的存在是的仍然能继续更新答案(可能需要特判横坐标相同的情况,或者在排序时修改排序函数)

而在单调队列获取答案的时候,则需要保证head > tail,因为当队列中仅存在一个点时,当取两点进行斜率比较时

将会取到head + 1,进行比较,而显然head + 1为队外元素(即非法),因此仅当队列中至少存在两个元素时才能弹队

  其次是CDQ分治的顺序

模拟54T4中是先分治两侧,目的是保证有序,而本题需要先分治左侧,处理完当前区间后再处理右侧

原因在于模拟54T4的转移是不需要顺序的,只需要将前缀中所有元素进行转移即可

而对于本题而言,转移是存在顺序的,即必须从左往右转移,因为每个点需要继承之前点的贡献

(所以由于处理完当前区间后排序已经被打乱,需要重新对右区间进行排序)

  另外还有一个不同点在于维护顺序

模拟54T4是先维护完单调栈再从右侧区间逐一进行弹栈取答案,原因在于其取答案并没有限制,即对于右侧区间所有点,取答案的条件是统一的

而对于本题而言,需要一边维护单调队列,一边取答案,因为显然,对于右侧区间内某点i,取答案的一个条件为id(j) < id(i),也就是说右侧区间取答案的条件不统一

可以发现,若先维护队列再取答案,由于弹队列不存在id限制,那么可能对于i点的可行答案会被弹走,因此会漏情况

代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define I long long
 4 #define C char
 5 #define B bool
 6 #define V void
 7 #define LL long long
 8 #define P pair<I,I>
 9 #define MP make_pair
10 #define fir first
11 #define sec second
12 #define g(x) (f[x] - x * (x + 1) / 2)
13 const I N = 1e5 + 3;
14 I n,q[N],ans(LONG_LONG_MIN),f[N];
15 struct L {I a,b;} a[N];
16 inline I read() {
17     I x(0),y(1); C z(getchar());
18     while (!isdigit(z)) { if (z == '-') y = -1; z = getchar(); }
19     while ( isdigit(z))  x = x * 10 + (z ^ 48), z = getchar();
20     return x * y;
21 }
22 inline V Max (I &a,I b) { a = a > b ? a : b; }
23 inline V Min (I &a,I b) { a = a < b ? a : b; }
24 inline I max (I a,I b) { return a > b ? a : b; }
25 inline I min (I a,I b) { return a < b ? a : b; }
26 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; }
27 inline B com1 (const L &a,const L &b) { 
28     return a.a == b.a ? a.b < b.b : a.a < b.a; 
29 }
30 inline B com2 (const L &a,const L &b) { return a.b < b.b; }
31 inline B Check1 (I i,I j,I k) {
32     return (g(i) - g(j)) * (j - k) >= (g(j) - g(k)) * (i - j);
33 }
34 inline B Check2 (I k,I i,I j) {
35     return k * (i - j) >= g(j) - g(i); 
36 }
37 V Divide (I l,I r) {
38     if (l == r) return ;
39     I mid (l + r >> 1),h(1),t(0),p1(l);
40     Divide (l,mid); 
41     sort (a + l,a + mid + 1,com2);
42     sort (a + mid + 1,a + r + 1,com2);
43     for (I i(mid + 1);i <= r; ++ i) {
44         while (p1 <= mid && a[p1].b < a[i].b) {
45             while (h <= t && Check1 (a[p1].b,a[q[t]].b,a[q[t - 1]].b)) t -- ; q[++t] = p1 ++ ; 
46         }
47         while (h <  t && Check2 (a[i].b,a[q[h + 1]].b,a[q[h]].b)) h ++ ;
48         if (h > t) continue;
49         Max (f[a[i].b],f[a[q[h]].b] + a[i].a - (a[i].b - a[q[h]].b) * (a[i].b - a[q[h]].b - 1) / 2);
50     }
51     sort (a + mid + 1,a + r + 1,com1);
52     Divide (mid + 1,r);
53 } 
54 signed main () {
55     freopen ("skip.in","r",stdin);
56     freopen ("skip.out","w",stdout);
57     n = read();
58     for (I i(1);i <= n; ++ i) 
59         a[i] = (L){read(),i}; 
60     for (I i(1);i <= n; ++ i)
61         f[i] = a[i].a - i * (i - 1) / 2;
62     sort (a + 1,a + n + 1,com1);
63     Divide (1,n);
64     for (I i(1);i <= n; ++ i)
65         Max (ans,f[i] - (n - i + 1) * (n - i) / 2);
66     Max (ans,-(n + 1) * n / 2);
67     printf ("%lld\n",ans);
68 }
View Code

 

标签:return,NOIP,55,mid,队列,inline,维护,模拟,define
来源: https://www.cnblogs.com/HZOI-LYM/p/15306999.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有