T1:
将问题分层考虑,显然我们可以求出最大得分,利用
前趋贪心即可,于是考虑在最大得分下,如何使字典序最
大,显然我们可以考虑在换牌的情况下对最大得分有无影
响,发现其具有单调性,于是在使用线段树维护最大得分
进行check的同时二分满足条件的最大得分即可
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:
发现问题具有明显的子结构,即无论最大值在哪,最小
值都必须移动到左右两侧,再次之后,次小值将继续这一进
程,故发现只要不断重复这一进程即可。
维护权值与距离边界距离,采取最优决策即可
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,其省略了背包容量的枚举,因为在所有转移满
足最大性的情况下可以直接合并转移
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优化,问题提示,最优问题可以转化为差分进行维护,最
优性问题整体合并降低复杂度。