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\) 越大越好。因此只需要求 最大團 即可.