NOIP模拟31

T1:

  将问题分层考虑,显然我们可以求出最大得分,利用

前趋贪心即可,于是考虑在最大得分下,如何使字典序最

大,显然我们可以考虑在换牌的情况下对最大得分有无影

响,发现其具有单调性,于是在使用线段树维护最大得分

进行check的同时二分满足条件的最大得分即可

NOIP模拟31
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define I int
 4 #define V void
 5 const I N = 1e5 + 5;
 6 I n;
 7 struct SGT { I a[N << 2],b[N << 2],s[N << 2];
 8     #define lid id << 1
 9     #define rid id << 1 | 1
10     #define mid (l + r >> 1)
11     inline V update (I id) {
12         I pub (min (a[rid],b[lid]));
13         a[id] = a[lid] + a[rid] - pub;
14         b[id] = b[lid] + b[rid] - pub;
15         s[id] = s[lid] + s[rid] + pub;
16     }
17     V poimod_A (I id,I l,I r,I pos,I key) {
18         if (l == r) return (V) (a[id] += key);
19         pos <= mid ? poimod_A (lid,l,mid,pos,key) : poimod_A (rid,mid + 1,r,pos,key);
20         update (id);
21     }
22     V poimod_B (I id,I l,I r,I pos,I key) {
23         if (l == r) return (V) (b[id] += key);
24         pos <= mid ? poimod_B (lid,l,mid,pos,key) : poimod_B (rid,mid + 1,r,pos,key);
25         update (id);
26     }
27     #undef mid 
28     #undef lid
29     #undef rid
30 }SGT;
31 signed main () { I a[N],b[N]; multiset <I> s;
32     cin >> n;
33     for (I i(1);i <= n; ++ i) cin >> b[i], SGT.poimod_B (1,1,N,b[i],1);
34     for (I i(1);i <= n; ++ i) cin >> a[i], SGT.poimod_A (1,1,N,a[i],1), s.insert (a[i]);
35     I tmp (SGT.s[1]);
36     for (I i(1);i <= n; ++ i) {
37       SGT.poimod_B (1,1,N,b[i],-1);
38       I l(b[i] + 1), r(*--s.end ());
39       while (l < r) { I mid (l + r + 1 >> 1);
40         SGT.poimod_A (1,1,N,mid,-1);
41         SGT.s[1] + 1 == tmp ? l = mid : r = mid - 1;
42         SGT.poimod_A (1,1,N,mid,1);
43       }
44       SGT.poimod_A (1,1,N,l,-1);
45       if (l <= r && SGT.s[1] + 1 == tmp) { printf ("%d ",l); -- tmp; s.erase (s.find (l)); }
46       else {
47         SGT.poimod_A (1,1,N,l,1);
48         I l(1), r(b[i]);
49         while (l < r) { I mid (l + r + 1 >> 1);
50           SGT.poimod_A (1,1,N,mid,-1);
51           SGT.s[1] == tmp ? l = mid : r = mid - 1;
52           SGT.poimod_A (1,1,N,mid,1);
53         }
54         SGT.poimod_A (1,1,N,l,-1);
55         printf ("%d ",l);
56         s.erase (s.find (l));
57       }
58     }
59 }
View Code

分层考虑,线段树维护辅助二分

T2:

  发现问题具有明显的子结构,即无论最大值在哪,最小

值都必须移动到左右两侧,再次之后,次小值将继续这一进

程,故发现只要不断重复这一进程即可。

  维护权值与距离边界距离,采取最优决策即可

NOIP模拟31
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define I int
 4 #define V void
 5 const I N = 1e5 + 5;
 6 I n;
 7 struct BIT { I c[N];
 8     #define lowbit(x) (x & -x)
 9     inline V insert (I x,I y) { for ( ;x <= n;x += lowbit(x)) c[x] += y; }
10     inline I secsum (I x) { I res(0);
11         for ( ; x ;x -= lowbit(x)) res += c[x];
12         return res;
13     }
14 }BIT;
15 signed main() { I upd,res; deque <I> q[N];
16     cin >> n;
17     for (I i(1),data;i <= n; ++ i) cin >> data, q[data].push_back(i), BIT.insert (i,1), upd = max (upd,data);
18     for (I i(1);i <= upd; ++ i) while (q[i].size ()) { 
19       I x(q[i].front ()), y(q[i].back ()), tmp1(BIT.secsum (x - 1)), tmp2(BIT.secsum (n) - BIT.secsum (y));
20       tmp1 < tmp2 ? (res += tmp1, BIT.insert (x,-1), q[i].pop_front ()) : (res += tmp2, BIT.insert (y,-1), q[i].pop_back ()); 
21     }
22     cout << res << endl;
23 }
View Code

问题子结构性质,维护与最优决策

T3:

  包含或不相交,显然在提示树形结构,于是可以进行树

形DP,发现并不必要,可以转化到序列问题进行考虑,DP

很显然,然而复杂度过不去,考虑优化。

  发现问题中要求最大美观程度,于是可以转化DP,采取

差分形势进行优化,因为在最优条件下,差分数组必然单调

不降,于是DP过程中可以利用大根堆进行整体转移,相较于

传统背包DP,其省略了背包容量的枚举,因为在所有转移满

足最大性的情况下可以直接合并转移

NOIP模拟31
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define I int
 4 #define V void
 5 #define LL long long
 6 const I N = 3e5 + 5;
 7 I n,m,val[N],tot,head[N],to[N],nxt[N];
 8 struct LINE {
 9     I id,l,r;
10     friend inline bool operator < (const LINE &a,const LINE &b) { 
11         return a.l == b.l ? a.r > b.r : a.l < b.l;
12     }
13 }line[N];
14 LL sup[N];
15 priority_queue <LL> q[N];
16 multiset <LINE> s;
17 multiset <LINE> :: iterator it;
18 inline V found1 (I x,I y) {
19     to[++tot] = y,nxt[tot] = head[x],head[x] = tot;
20 }
21 V found2 (I id) {
22     while (!s.empty ()) {
23       it = s.lower_bound (line[id]);
24       if (it == s.end ()) break;
25       LINE tmp = *it;
26       if (tmp.l >= line[id].l && tmp.r <= line[id].r)
27         s.erase (it), found1 (id,tmp.id), found2 (tmp.id);
28       else break;
29     }
30 }
31 V dfs (I x) {
32     I s(m + 1); 
33     for (I i(head[x]),y(to[i]); i ;i = nxt[i],y = to[i]) {
34       dfs (y); if (q[y].size () > q[s].size ()) s = y;
35     }
36     swap (q[x],q[s]);
37     for (I i(head[x]),y(to[i]); i ;i = nxt[i],y = to[i]) if (y != s) {
38       I tmp (q[y].size ());
39       for (I i(1);i <= tmp; ++ i) sup[i] = q[x].top (), q[x].pop ();
40       for (I i(1);i <= tmp; ++ i) sup[i] += q[y].top (), q[y].pop ();
41       for (I i(1);i <= tmp; ++ i) q[x].push (sup[i]); 
42     }
43     q[x].push (val[x]);
44 }
45 signed main () { 
46     scanf ("%d%d",&n,&m);
47     for (I i(1);i <= m; ++ i) {
48       scanf ("%d%d%d",&line[i].l,&line[i].r,&val[i]);
49       line[i].id = i, s.insert (line[i]);
50     }
51     line[0] = (LINE) {0,1,n}; found2 (0); dfs (0); I tmp (q[0].size ()); memset (sup,0,sizeof sup);
52     for (I i(1);i <= tmp; ++ i) sup[i] = q[0].top (), q[0].pop ();
53     for (I i(1);i <= m; ++ i) sup[i] += sup[i - 1], printf ("%lld ",sup[i]);
54 }
View Code

DP优化,问题提示,最优问题可以转化为差分进行维护,最

优性问题整体合并降低复杂度。

上一篇:最小费用最大流解决KM匹配问题


下一篇:【20210709】“去QE”时代下,QE如何破茧重生?