bzoj十一月月赛
有n轮游戏,第i轮游戏有权值w[i](可正可负),如果选择玩第i次游戏,并且这是第k次玩这个游戏,那么会获得$w_i(k^2+ak+b)$点分数。
你需要输出恰好玩1…n轮游戏最多能获得多少分。n<=1e5,a^2>=4b。
首先a^2>=4b显然只是在告诉我们k^2+ak+b非负,因为如果有负的负负得正就很尴尬了。 a^2>=4b好像没啥用
然后我们可以发现最优解是可以通过增量法构造的,就是说对于k个元素的最优解,存在一种k+1个元素的最优解比这个最优解多一个元素。证明大约如下:
那么我们可以考虑从k=0开始每次选择一个元素加进去,作为k+1的方案。
假设加完了,那我们把每次加的元素排成一排,设f[k]表示选k个元素的方案价值,g[k]=f[k]-f[k-1],那么g应该单调不上升(由于答案是凸的)。那么我们考虑对于一个新的元素,啥时候应该把它加进去,我们发现我们可以直接追踪这个g,二分到一个位置使得g单调不上升。
考虑这个元素加进去之后会有什么影响。容易发现一个元素插到某个位置之后,前面的g显然没有影响,对于后面的g,这个元素企图篡权夺位失败,每次失败都要后移一位。
那么对于一个后面的g,假设它原来的rank为r,g'=g+(v[r+1]-v[r])*刚插入的w=g+(2r+a+1)*刚插入的w,r'=r+1。splay上打标记维护即可。打标记的时候需要格外小心,因为多个标记合并的时候rank改变是有先后顺序的,详见代码吧。
#include <iostream> #include <stdio.h> #include <math.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <string> #include <bitset> #include <vector> #include <set> #include <map> #include <queue> #include <algorithm> #include <sstream> #include <stack> #include <iomanip> using namespace std; #define pb push_back #define mp make_pair typedef pair<int,int> pii; typedef long long ll; typedef double ld; typedef vector<int> vi; #define fi first #define se second #define fe first #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);} #define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);} #define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);} #define es(x,e) (int e=fst[x];e;e=nxt[e]) #define esb(x,e,b) (int e=fst[x],b=vb[e];e;e=nxt[e],b=vb[e]) #define SZ 666666 int an=0,ch[SZ][2],fa[SZ],sz[SZ],root,rk[SZ]; ll g[SZ],dgr[SZ],dg[SZ]; int dr[SZ]; void sett(int x,int r,ll gr,ll gg) { if(!x) return; g[x]+=gr*rk[x]+gg; rk[x]+=r; dgr[x]+=gr; dg[x]+=gg+gr*dr[x]; dr[x]+=r; } inline void pd(int x) { sett(ch[x][0],dr[x],dgr[x],dg[x]); sett(ch[x][1],dr[x],dgr[x],dg[x]); dr[x]=dgr[x]=dg[x]=0; } void upd(int x) {if(!x) return; sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;} void rot(int x) { if(!fa[x]) return; int y=fa[x],f=fa[y],p=ch[y][1]!=x; fa[x]=f; fa[y]=x; if(f) ch[f][ch[f][1]==y]=x; int g=ch[x][p]; ch[x][p]=y; ch[y][!p]=g; if(g) fa[g]=y; upd(y); upd(x); upd(f); } int ss[SZ],sn=0; void splay(int x,int f=0) { for(int y=x;y!=f;y=fa[y]) ss[++sn]=y; while(sn) pd(ss[sn--]); while(fa[x]!=f) { int y=fa[x]; if(fa[y]!=f) (ch[fa[y]][1]==y^ch[y][1]==x) ?rot(x):rot(y); rot(x); } if(!f) root=x; } int n,a,b,w[SZ]; ll v[SZ]; void ins(int x,int p,int a) { while(1) { ++sz[x]; pd(x); int r=(g[x]>=v[rk[x]]*ll(a)); if(!ch[x][r]) {ch[x][r]=p; sz[p]=1; fa[p]=x; return;} x=ch[x][r]; } } ll ans[SZ]; void dfs(int x) { if(!x) return; pd(x); ans[rk[x]]=g[x]; dfs(ch[x][0]); dfs(ch[x][1]); } int main() { scanf("%d%d%d",&n,&a,&b); for(int i=1;i<=n;++i) scanf("%d",w+i), v[i]=(i+a)*(ll)i+b; sz[1]=rk[1]=root=1; g[1]=w[1]*v[1]; for(int i=2;i<=n;++i) { ins(root,i,w[i]); splay(i); rk[i]=sz[ch[i][0]]+1; g[i]=(ll)v[rk[i]]*w[i]; sett(ch[i][1],1,w[i]*2,(a+1)*ll(w[i])); } dfs(root); for(int i=2;i<=n;++i) ans[i]+=ans[i-1]; for(int i=1;i<=n;++i) printf("%lld ",ans[i]); }