Codeforces 626G

注意到在同一堆中放彩票的贡献是单调递减的,因此如果没有修改,可以用堆贪心求出最大期望收益。
考虑修改操作,如果将 l k l_k lk减小 1 1 1,在第 k k k堆放的数目可能不变,减小 1 1 1(原先放了 l k l_k lk张),或是增加若干张。我们断言若增加,只会增加 1 1 1张,证明是假设原先放了 c c c张,现在若放了 c + 2 c+2 c+2张以上,那么第 c + 2 c+2 c+2张一定替换了其他堆的某张彩票,设那张彩票的贡献为 w w w,由于原先不能放第 c + 1 c+1 c+1张,因此有 p k ( c + 1 ( c + 1 ) + l k − c c + l k ) ≤ w p_k(\frac{c+1}{(c+1)+l_k}-\frac{c}{c+l_k})\leq w pk((c+1)+lkc+1c+lkc)w,而 p k ( c + 2 ( c + 2 ) + ( l k − 1 ) − c + 1 ( c + 1 ) + ( l k − 1 ) ) < p k ( c + 1 ( c + 1 ) + l k − c c + l k ) p_k(\frac{c+2}{(c+2)+(l_k-1)}-\frac{c+1}{(c+1)+(l_k-1)})pk((c+2)+(lk1)c+2(c+1)+(lk1)c+1)<pk((c+1)+lkc+1c+lkc),于是替换后并没有变优。将 l k l_k lk增加 1 1 1同理。
这样我们知道每次修改后至多变化 1 1 1张彩票,用数据结构维护增量最值即可。
时间复杂度 O ( ( n + t + q ) log ⁡ n ) \mathcal O((n+t+q)\log n) O((n+t+q)logn)

#include 
#define FR first
#define SE second

using namespace std;

typedef double db;
typedef pair<db,int> pr;

int val[200005],r[200005];
int size[200005],k;

set <pr> st1,st2;
bool in1[200005],in2[200005];
pr a[200005],b[200005];

void modify(int x,int v) {
  if (in1[x]) st1.erase(a[x]);
  if (in2[x]) st2.erase(b[x]);
  size[x]+=v;
  if (size[x]<r[x]) {
  	a[x]=pr(((db)(size[x]+1)/(size[x]+r[x]+1)-(db)size[x]/(size[x]+r[x]))*val[x],x);
  	st1.insert(a[x]);
  	in1[x]=1;
  }
  else in1[x]=0;
  if (size[x]) {
  	in2[x]=1;
  	b[x]=pr(((db)size[x]/(size[x]+r[x])-(db)(size[x]-1)/(size[x]+r[x]-1))*val[x],x);
  	st2.insert(b[x]);
  }
  else in2[x]=0;
  k-=v;
}

db increase(int x,bool v) {
  db t=((db)(size[x]+1)/(size[x]+r[x]+1)-(db)size[x]/(size[x]+r[x]))*val[x];
  int id=0;
  if (!k) {
  	if (st2.empty()) return -1e60;
  	set<pr>::iterator it=st2.begin();
  	if (it->SE==x) it++;
  	if (it==st2.end()) return -1e60;
  	id=it->SE;
  	t-=it->FR;
  }
  if (v) {
    modify(x,1);
    if (id) modify(id,-1);
  }
  return t;
}

db decrease(int x,bool v) {
  db t=((db)(size[x]-1)/(size[x]+r[x]-1)-(db)size[x]/(size[x]+r[x]))*val[x];
  int id=0;
  if (st1.size()>1||(st1.size()==1&&(st1.begin())->SE!=x)) {
  	set<pr>::iterator it=st1.end();
  	it--;
  	if (it->SE==x) it--;
  	id=it->SE;
  	t+=it->FR;
  } 
  if (v) {
  	modify(x,-1);
  	if (id) modify(id,1);
  }
  return t;
}

int main() {
  int n,m;
  scanf("%d%d%d",&n,&k,&m);
  for(int i=1;i<=n;i++) scanf("%d",&val[i]);
  for(int i=1;i<=n;i++) scanf("%d",&r[i]);
  for(int i=1;i<=n;i++) {
  	in1[i]=1;
  	a[i]=pr(1.0/(1.0+r[i])*val[i],i);
  	st1.insert(a[i]);
  }
  db ans=0;
  while (k&&st1.size()) {
  	int x=(st1.rbegin())->SE;
  	ans+=(st1.rbegin())->FR;
  	modify(x,1);
  }
  for(int i=1;i<=m;i++) {
  	int kind,x;
  	scanf("%d%d",&kind,&x);
  	ans-=(db)size[x]/(size[x]+r[x])*val[x];
  	if (kind==1) r[x]++; else r[x]--;
  	ans+=(db)size[x]/(size[x]+r[x])*val[x];
  	db v=((size[x]<=r[x])?0:-1e60);
  	int op=0;
  	if (size[x]<r[x]) {
  		db t=increase(x,0);
  		if (t>v) {
  			v=t;op=1;
		  }
	  }
	if (size[x]) {
		db t=decrease(x,0);
		if (t>v) {
			v=t;op=2;
		}
	}
	ans+=v;
	printf("%.10f\n",(double)ans);
	if (!op) modify(x,0);
	if (op==1) increase(x,1);
	if (op==2) decrease(x,1);
  }
  return 0;
}

你可能感兴趣的:(集训队作业,codeforces,贪心)