首页 > 其他分享 >CF912D 小鱼仔 题解

CF912D 小鱼仔 题解

时间:2022-11-03 21:57:14浏览次数:75  
标签:cur 题解 ll son fa 小鱼 vul root CF912D

这是一个很邪门的贪心
考虑到最终答案是每个正方形的贡献除以总的正方形个数,而正方形个数容易计算,那么只需最大化贡献。
从题面给出的图易得 每个点被覆盖的次数是一定的,我们只需要在被覆盖最多的点上面放置小鱼即可让答案最大化

接着容易想到一个暴力的做法,就是 \(n^2\) 统计每个点的贡献,取前 \(k\) 个点放置小鱼。
再考虑优化,每个点被覆盖情况实际上可以看成长和宽的被覆盖情况的乘积,我们把正方形看成是两条线段,分别覆盖在长和宽上,这样的两条线段对应原矩形中唯一一个正方形。设长和宽被覆盖次数为两个序列 \(a_i\) \(b_j\) ,原矩形为 \(c_{i,j}\) ,那么 \(c_{i,j}=a_i * b_j\) , 我们的任务就是计算出前 \(k\) 大的 \(c_{i,j}\) ,考虑把 \(a_i\) \(b_j\) 排序,从大到小分别枚举 \(i\) ,\(j\) 把对应的乘积放入平衡树或者 \(set\) 。考虑到我们是从大到小枚举,如果一个乘积 \(a_i * b_j\) 在平衡树中的排位大于 \(k\) ,继续下去的话乘积只会更小,那么他自己和他后面的元素也就都没有价值了,我们直接 \(break\) 掉,这个做法时间复杂度目测不会超过 \(n \sqrt{n} log{n}\) ,实际测试跑的快得多。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
typedef long long ll;
using namespace std;
ll n,m,k,r,a[400001],b[400001],ans;

struct Splay{
	#define N (ll)3e6
	ll siz[N],fa[N],son[N][2],vul[N],tot,root,cnt[N];
	void UP(ll x){
		siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x];
	}
	bool dir(ll x){
		return son[fa[x]][1]==x;
	}
	void rotate(ll x){
		ll y=fa[x],z=fa[y],k=dir(x),w=son[x][k^1];
		fa[x]=z,son[z][dir(y)]=x;
		fa[y]=x,son[x][k^1]=y;
		fa[w]=y,son[y][k]=w;
		UP(y),UP(x); 
	}
	void splay(ll x,ll goal=0){
		while(fa[x]!=goal){
			ll y=fa[x],z=fa[y];
			if(z!=goal){
				if(dir(x)==dir(y))rotate(y);
				else rotate(x);
			}
			rotate(x);
		}
		if(!goal)root=x;
	}
	void find(ll x){
		if(!root)return ;
		ll cur=root;
		while(son[cur][x>vul[cur]]&&x!=vul[cur])
			cur=son[cur][x>vul[cur]];
		splay(cur);
	}
	ll LR(ll x,ll k){
		find(x);
		if(vul[root]<x&&k==0)return root;
		if(vul[root]>x&&k==1)return root;
		ll cur=son[root][k];
		while(son[cur][k^1])cur=son[cur][k^1];
		return cur;
	}
	ll insert(ll x){
		ll cur=root,p=0;
		while(cur&&x!=vul[cur]){
			p=cur;
			cur=son[cur][x>vul[cur]];
		}
		if(cur)cnt[cur]++;
		else {
			cur=++tot;
			if(p)son[p][x>vul[p]]=cur;
			siz[cur]=cnt[cur]=1;
			fa[cur]=p,vul[cur]=x;
			son[cur][0]=son[cur][1]=0;
		}
		splay(cur);
	}
	void Delete(ll x){
		ll le=LR(x,0),re=LR(x,1);
		splay(le),splay(re,le);
		ll del=son[re][0];
		if(cnt[del]>1)cnt[del]--,splay(del);
		else son[re][0]=0;
		UP(re),UP(le);
	}
	ll get_rank(ll x){
		find(x);
		if(vul[root]>=x)return siz[son[root][1]]+cnt[root];
		return siz[son[root][1]];
	}
}T;

int main(){
	T.insert(-1e15);
	T.insert(1e15);
	cin>>n>>m>>r>>k;
	for(ll i=1;i<=n-r+1;i++)a[i]++,a[i+r]--;
	for(ll i=1;i<=m-r+1;i++)b[i]++,b[i+r]--;
	for(ll i=1;i<=n;i++)a[i]+=a[i-1];
	for(ll i=1;i<=m;i++)b[i]+=b[i-1];
	sort(1+a,1+a+n);
	sort(1+b,1+b+m);
	for(ll i=n;i>=1;i--){
		for(ll j=m;j>=1;j--){
			ll sum=a[i]*b[j];
			if(T.get_rank(sum)>k+1)break;
			T.insert(sum);
		}
	}
	while(k--){
		ll cur=T.LR(1e12,0);
		ans+=T.vul[cur];
		T.Delete(T.vul[cur]);
	}
	long double Ans=1.0*ans/(n-r+1)/(m-r+1);
	printf("%.10Lf",Ans);
}

标签:cur,题解,ll,son,fa,小鱼,vul,root,CF912D
From: https://www.cnblogs.com/caijiLYC/p/16855976.html

相关文章

  • ckeditor粘贴word图片问题解决
    ​ 自动导入Word图片,或者粘贴Word内容时自动上传所有的图片,并且最终保留Word样式,这应该是Web编辑器里面最基本的一个需求功能了。一般情况下我们将Word内容粘贴到Web编辑......
  • [ARC087F] Squirrel Migration 题解
    [ARC087F]SquirrelMigration给你一个\(n\)个节点的树,求一个\(1\simn\)的排列\((p_1,p_2,\dotsp_n)\),使得\(\sumdist(i,p_i)\)最大。求这样的排列个数。答案......
  • 【题解】P8818 [CSP-S 2022] 策略游戏
    【题解】P8818[CSP-S2022]策略游戏这道题应该是CSP-S2022所有题里面最简单的一道了,主要是有点套路,刨开套路,其实就是个静态维护区间最大最小值的板子。作为一名场外......
  • [题解] HDU7060 Separated Number 思路整理
    题目链接HDU7060SeparatedNumber题目大意给一个\(n\)位数,把该数字分成\(k\)段,每种方案的贡献为其分割出的段的数字之和。求所有分法的贡献之和(对\(998244353\)......
  • java 中文乱码问题解决思路
    碰到中文乱码,引起的原因一般为,在编写程序的时候的编码方式与查看的时候的编码方式不一致,从而导致了中文乱码。碰到这种问题,首先要做的就是查看自己编码方式,以String为例St......
  • 2022.11.2 模拟赛题解
    简要题意给定一棵\(n\)个节点的有根树,树根为\(1\)号节点,每个结点有一个权值\(a_i(|a_i|\leq10^9)\),求包含\(1\)的前\(k\)小的连通块的权值。简要题解前置内......
  • 11.2 解题报告&CSP-S 2022题解
    T1用时:\(1\)h期望得分:\(70\)~\(80\)实际得分:\(55\)这题考场写了个常数比较小的\(O(n^3)\)的做法,期望得分\(75\)左右,但是由于bfs忘记打标记导致MLE和TLE,挂......
  • P8671 [蓝桥杯 2018 国 AC] 约瑟夫环 题解
    约瑟夫环有\(\mathcalO(n)\)做法相信大家都知道。这里就不在介绍了,这里给出一个不知道这个结论的\(\mathcalO(n\logn)\)简单做法。考虑直接模拟题意,每次循环往后数......
  • [题解]CF1327F
    首先拆位,然后考虑限制会带来什么。要求与起来是\(1\)的必须全是\(1\),差分打个标记。要求与起来是\(0\)的必须至少有一个\(0\),考虑如何计数。计数问题有可能是动态......
  • CF1729G Cut Substrings 题解
    CF1729GCutSubstrings给出两个字符串\(s,t\),每次可以将字符串\(s\)中任意一个为\(t\)的子串删除,删除位置的字符变为空格(或理解为无实义)。求最少删除几次可以使得......