暑假集训 加赛1

A.修仙(restart)

注意到这个题显然可以开一个优先队列来每次选取最优的解(对结果贡献最大的,显然也是值最大的),但是我们会发现能卡掉这个算法:

4 7
3 4 4 3

显然是应该选两边的.

直接考虑的话太麻烦了,因此我们考虑做一个反悔.

不难发现,对于每一组来说的更优策略只出现在不选它,而选它的左右组合的时候. 因此我们在每次选出一个新的组合的时候,都向优先队列内插入一个值,用来表示 “取消选择当前值,而选择它的左右组合所带来的价值贡献”,即 “左方组合贡献+右方组合贡献-当前贡献”,假如这个贡献比优先队列中任何一个贡献都优,那么我们就采用这个返回方案.

这样做的话我们就不存在不能选的点了(任何一个点在优先队列中都有对应的节点,只不过当合并后,两个点会缩成一个),因此我们可以考虑用双向链表来维护这样的序列.

赛时初始化的值太小了... 应该直接 memset 的.

这个题细节太多了

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int inf=0x3f3f3f3f3f3f3f3f;
int n,x,sum;
int a[200001],gx[200001];
struct node{
	int leftid,w;
	bool operator <(const node &A)const{
		if(w==A.w) return leftid<A.leftid;
		return w<A.w; //
	}
};
priority_queue<node>q;
int l[200001],r[200001];
bool hadcon[200001];
void connect(int x){ //x and x+1 make_pair
/*
 -        -     -      -     -
l[l[x]]   l[x]  x-----r[x]  r[r[x]]
*/
	r[l[l[x]]]=x;
	l[r[r[x]]]=x;
	gx[x]=gx[l[x]]+gx[r[x]]-gx[x];
	hadcon[l[x]]=hadcon[r[x]]=1;
	l[x]=l[l[x]];
	r[x]=r[r[x]];
}
void print(priority_queue<node>p){
	while(!p.empty()){
		node u=p.top();p.pop();
		cout<<u.leftid<<" "<<u.w<<endl;
	}
	cout<<endl;
}
signed main(){
//	freopen("restart3.in","r",stdin);
//	freopen("out.out","w",stdout);
	cin>>n>>x;
	for(int i=1;i<=n;++i){
		cin>>a[i];sum+=a[i];
		if(i!=1){
			gx[i-1]=a[i]+a[i-1]-max(a[i]+a[i-1]-x,0ll);
		}
	}
	for(int i=1;i<=n-1;++i){
		l[i]=i-1;
		r[i]=i+1;
//		cout<<" push "<<i<<" "<<gx[i]<<endl;
		q.push({i,gx[i]});
	}
	gx[0]=-inf;gx[n]=-inf;
	l[0]=n;r[n]=0;r[0]=1;l[n]=n-1;
	for(int k=1;k<=n/2;++k){
//		print(q);
		while(q.size() and hadcon[q.top().leftid]){
			q.pop();
		}
		if(q.size()){
//			cout<<"conn "<<q.top().leftid<<endl;
			node u=q.top();q.pop();
			sum-=u.w;
			connect(u.leftid);
			q.push({u.leftid,gx[u.leftid]});
		}
		cout<<sum<<endl;
	}
}
/*
6 10
5 6 3 5 4 5

8 6
3 3 2 5 5 2 3 3 

8 6
3 3 4 3 3 4 3 3
*/ 

B.七负我

考虑两个没有边的点 \((u, v)\) ,设与 \(u\) 相连的点 \(t_i\) 的和为 \(a\) ,设与 \(v\) 相连的点 \(t_i\) 的和为 \(b\) ,那么这两个点原先的贡献为 \(t_u\times a + t_v\times b\) ,容易发现清空贡献较小的点可以使贡献变为 \((t_u + t_v)\times \max(a, b)\) 。不断进行这样的操作,最终只剩下一个团。

设团的大小为 \(n\) ,则边数为 \(\tfrac{n\times (n - 1)}{2}\) ,显然总贡献为 \((\tfrac{T}{n})^2\times \tfrac{n\times (n - 1)}{2}\) ,简单化简发现 \(n\) 越大越好。因此只需要求 最大团 即可.

posted @ 2024-07-22 06:46  HaneDaniko  阅读(21)  评论(3编辑  收藏  举报