暑假集训 加赛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\) 越大越好。因此只需要求 最大团 即可.