首页 > 其他分享 >Codeforces 1787H - Codeforces Scoreboard(平衡树优化 dp)

Codeforces 1787H - Codeforces Scoreboard(平衡树优化 dp)

时间:2023-06-26 10:59:27浏览次数:58  
标签:ch int 1787H sum Scoreboard Codeforces ncnt siz lz

令 \(c_i=b_i-a_i\),等价于我们钦定一个排列 \(p\),最小化 \(\sum \min(p_ik_i,c_i)\),拿 \(\sum b_i\) 减去之就是答案。

我们钦定一些 \(i\) 满足 \(p_ik_i<c_i\),根据排序不等式,这些 \(p_i\) 肯定按 \(k\) 从大到小的顺序依次填入 \(1,2,3,\cdots\)。这样就可以 DP 了:将 \(k\) 从大到小排序,然后设 \(dp_{i,j}\) 表示考虑前 \(i\) 道题,钦定了 \(j\) 道的最小代价,有 \(dp_{i,j}=\min(dp_{i-1,j-1}+jk_i,dp_{i-1,j}+c_i)\)。最终答案为 \(\sum b_i-\min dp_{n,i}\)。

考虑优化,记 \(g_{i,j}=f_{i,j}-f_{i,j-1}(1\le j\le i)\),那么 \(f_{i,0}+\sum\limits_{t=1}^jg_{i,t}=\min(f_{i-1,0}+\sum\limits_{t=1}^{j-1}dp_{i-1,t}+jk_i,f_{i-1,0}+\sum\limits_{t=1}^jdp_{i-1,t}+c_i)\)。考虑前者比后者更小的充要条件——相当于 \(jk_i<g_{i-1,j}+c_i\),令 \(h_{i,j}=g_{i-1,j}-jk_i+c_i\),发现 \(h_{i,j}\) 是先负后正的,这是因为 \(k\) 单调不增,导致 \(g_{i-1,j}\) 增长速度比 \(jk_i\) 快。也就是说,对于一段前缀,采用第二种转移,对于一段后缀,采取第一转移,二分找到分界点之后相当于一段后缀加一个数,中间再插入一个数。使用平衡树维护即可。

const int MAXN=2e5;
const ll INF=1e18;
mt19937 rng(114514);
int n;
struct dat{
	int a,b,c,k;
	friend bool operator <(const dat &X,const dat &Y){return X.k>Y.k;}
}a[MAXN+5];
struct node{int ch[2],siz,key;ll val,lz;}s[MAXN+5];
int ncnt,rt;
void pushup(int k){s[k].siz=s[s[k].ch[0]].siz+s[s[k].ch[1]].siz+1;}
int nwnd(ll v){++ncnt;s[ncnt].siz=1;s[ncnt].key=rng();s[ncnt].val=v;return ncnt;}
void tag(int k,int v){if(k)s[k].lz+=v,s[k].val+=v;}
void pushdown(int k){if(s[k].lz)tag(s[k].ch[0],s[k].lz),tag(s[k].ch[1],s[k].lz),s[k].lz=0;}
void split(int k,int K,int C,int sz,int &a,int &b){
	if(!k)return a=b=0,void();pushdown(k);
	if(s[k].val-1ll*(sz+s[s[k].ch[0]].siz+1)*K+C>=0)b=k,split(s[k].ch[0],K,C,sz,a,s[k].ch[0]),pushup(k);
	else a=k,split(s[k].ch[1],K,C,sz+s[s[k].ch[0]].siz+1,s[k].ch[1],b),pushup(k);
}
int merge(int a,int b){
	if(!a||!b)return a+b;pushdown(a);pushdown(b);
	if(s[a].key<s[b].key)return s[a].ch[1]=merge(s[a].ch[1],b),pushup(a),a;
	else return s[b].ch[0]=merge(a,s[b].ch[0]),pushup(b),b;
}
ll cur,mn;
void dfs(int k){
	if(!k)return;pushdown(k);dfs(s[k].ch[0]);
	cur+=s[k].val;chkmin(mn,cur);dfs(s[k].ch[1]);
}
void solve(){
	scanf("%d",&n);ll sumb=0;
	for(int i=1;i<=n;i++){
		scanf("%d%d%d",&a[i].k,&a[i].b,&a[i].a);
		a[i].c=a[i].b-a[i].a;sumb+=a[i].b;
	}
	sort(a+1,a+n+1);
//	for(int i=1;i<=n;i++)printf("! %d %d\n",a[i].k,a[i].c);
	for(int i=0;i<=ncnt;i++)s[i].ch[0]=s[i].ch[1]=s[i].siz=s[i].key=s[i].val=s[i].lz=0;
	ncnt=rt=0;ll f0=0;
	for(int i=1;i<=n;i++){
		int k1,k2;split(rt,a[i].k,a[i].c,0,k1,k2);tag(k2,a[i].k);
		rt=merge(merge(k1,nwnd(1ll*(s[k1].siz+1)*a[i].k-a[i].c)),k2);
		f0+=a[i].c;
	}cur=f0;mn=f0;dfs(rt);
	printf("%lld\n",sumb-mn);
}
int main(){
	int qu;scanf("%d",&qu);
	while(qu--)solve();
	return 0;
}
/*
1
6
1 8 1
9 29 4
2 14 3
4 13 1
2 19 5
10 12 5
*/

标签:ch,int,1787H,sum,Scoreboard,Codeforces,ncnt,siz,lz
From: https://www.cnblogs.com/tzcwk/p/Codeforces-1787H.html

相关文章

  • Educational Codeforces Round 150 (Rated for Div. 2) A-E
    比赛链接A代码#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;boolsolve(){intn;cin>>n;if(n<=4)cout<<"Bob"<<'\n';elsecout<<"Alice"<<......
  • CodeForces 1842E Tenzing and Triangle
    洛谷传送门CF传送门一个很显然的观察:选择的三角形两两重叠面积为\(0\),否则合并更优。考虑dp,设\(f_i\)为删完\(x_j\gei\)的所有点的最小花费。转移就枚举选择的三角形直角边长\(l\),那么\(f_i=\min(f_{i+1}+\sum\limits_{x_p=i}c_p,\min\limits_lf_{i+l}......
  • CodeForces 1842G Tenzing and Random Operations
    洛谷传送门CF传送门原来还不会这种拆期望的套路设\(b_j\)为第\(j\)次操作中选择的\(i\),所求即为\(E(\prod\limits_{i=1}^n(a_i+\sum\limits_{j=1}^m[b_j\lei]\timesv))\)。乘法也可以考虑拆期望。我们有最基础的性质\(E((a+b)\times(c+d))=E(ac)......
  • CodeForces 1842F Tenzing and Tree
    洛谷传送门CF传送门事实上自己方向一直是错的……绝对值不好弄,我一开始的想法是直接去绝对值,但是不可避免地要\(O(n^3)\)。考虑我们直接钦定黑点重心为根,设这个根为\(r\),设\(sz_i\)为\(i\)子树内黑点数,由重心的性质,可以直接去绝对值,也就是说答案为\(\sum\limits_{i\n......
  • Codeforces Round 875 (Div. 2) C. Copil Copac Draws Trees
    bfs解法如果是暴力求解的话就每次都扫描一次所有边直到所有点都和树连接优化:每次扫描我们可以发现会重复扫描那些已经存在树中的边了,因此我们可以只扫描还没有存在树中的边且是没扫过的边对于每次更新,比如由点a已经在树中,更新点b,我们只需判断点a被更新到树中点的编号和a-b边的......
  • Codeforces Round #879 (Div. 2) A-E
    比赛链接A代码#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;boolsolve(){intn;cin>>n;intcnt=0;for(inti=1;i<=n;i++){intx;cin>>x;if(x==-1)cnt++;......
  • Codeforces Round 781 (Div. 2) E. MinimizOR (可持久化字典树)
    传送门题目大意:  T组测试数据每组测试数据先输入一个n表示有一个长度为n的一维数组,然后输入n个数字表示这个一维数组。紧接着输入一个k表示有k个询问,对于每个询问会输入一个l和一个r表示询问数组中[l,r]这个区间里面任意两个下标不重复的元素最小的或(|)是多少。解题思路: ......
  • Codeforces Round 881 (Div
    E.TrackingSegments给定初始长度为n,且全为0的序列a,然后给出m个线段,如果一个线段中1的个数严格大于0的个数,那么该线段称为一个漂亮线段,现在给出q次操作,每次操作使得序列a中位置x上的0变为1,请你求出第一次使得所有线段中出现漂亮线段的询问题解:二分答案容易发现答案具有单......
  • Codeforces 1603D. Artistic Partition
    题目链接:D-ArtisticPartition题目大意:要求将\([1,n]\)分成\(k\)段,使得每段对应的\(c(l,r)\)之和最小,其中\(c(l,r)=\sum_{i=l}^r\sum_{j=i}^r[\gcd(i,j)\gel]\)。首先注意到当\(r<2l\)时,\(c(l,r)=r-l+1\)。所以当\(2^k-1\gen\)时答案即为\(n\)。考虑\(\texttt......
  • Codeforces Round 766 (Div. 2) 比赛报告
    0比赛经过比赛还没开始的时候就感觉状态不太好。果然。总归到底都是一个心态问题。A题经过看A题,结果半天看不懂,一开始没有注意到一定要在黑格子上操作。扔到DeepL上翻译了一下,再手玩一下样例就做出来了,速度有点慢。CF怎么这么喜欢出分讨题啊。看题目不能太急,要一个一......