首页 > 其他分享 >[SDOI2011] 拦截导弹

[SDOI2011] 拦截导弹

时间:2024-07-20 20:18:12浏览次数:6  
标签:拦截导弹 cnt int res1 mid SDOI2011 1D op

这是CDQ分治优化1D/1D动态规划的模板题(1D/1D动态规划的概念见OI-wiki)

一般来说,优化的1D/1D/动态规划,在转移的时候是由不等式作为条件的,所以可以像这样转化为三维偏序

用线段树进行如下维护:

1.维护区间最大值

2.查询区间最大值的某一数组的和

代码见下(一定要学会将数组翻转的操作)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=5e4+10;
const double eps=1e-5;
int n;
bool OP;
struct node
{
	int h,v,t;
}m[N];
int Max[N<<2],f[N][2],cnt,v[N],e[N];
double sum[N<<2],g[N][2];
bool cmp(node i,node j)
{
	return i.h>j.h;
}
void modify(int p,int l,int r,int x,int d,bool op,bool flag)
{
	if(l>x||r<x) return;
	if(l==r)
	{
		if(!flag) 
		{
			Max[p]=-1,sum[p]=0;
			return;
		}
		if(Max[p]<f[m[d].t][op])
		{
			Max[p]=f[m[d].t][op];
			sum[p]=g[m[d].t][op];
		}
		else if(Max[p]==f[m[d].t][op]) 	sum[p]+=g[m[d].t][op];
		return;
	}
	int mid=l+r>>1;
	modify(p<<1,l,mid,x,d,op,flag);
	modify(p<<1|1,mid+1,r,x,d,op,flag);
	if(Max[p<<1]>Max[p<<1|1]) sum[p]=sum[p<<1];
	else if(Max[p<<1]<Max[p<<1|1]) sum[p]=sum[p<<1|1];
	else sum[p]=sum[p<<1]+sum[p<<1|1];
	Max[p]=max(Max[p<<1],Max[p<<1|1]);
}
pair<int,double> ask(int p,int l,int r,int x,int y)
{
	if(l>y||r<x) return make_pair(-1,0);
	if(l>=x&&r<=y) return make_pair(Max[p],sum[p]);
	int mid=l+r>>1;
	pair<int,double> res1,res2;
	res1=ask(p<<1,l,mid,x,y);
	res2=ask(p<<1|1,mid+1,r,x,y);
	if(res1.first>res2.first) return res1;
	else if(res1.first<res2.first) return res2;
	else return make_pair(res1.first,res1.second+res2.second);
}
bool cmp1(node i,node j)
{
	if(!OP) return i.t<j.t;
	else return i.t>j.t;
	//这个排序想一下为什么这么写而不是直接写成i.t<j.t; 
}
void CDQ(int l,int r,bool op)
{
	if(l==r)
	{
		f[m[l].t][op]++;
		if(f[m[l].t][op]==1) g[m[l].t][op]=1;//这个导弹作为第一发 
		return;
	}
	int mid=l+r>>1;
	CDQ(l,mid,op);
	sort(m+l,m+mid+1,cmp);
	sort(m+mid+1,m+r+1,cmp);
	for(int i=l,j=mid+1;j<=r;j++)
	{
		while(i<=mid&&m[i].h>=m[j].h) 
		{
			modify(1,1,cnt,lower_bound(e+1,e+cnt+1,m[i].v)-e,i,op,1);
			//最后一个参数为1表示更新,为0表示还原 
			i++;
		}
		pair<int,double> nowmax=ask(1,1,cnt,lower_bound(e+1,e+cnt+1,m[j].v)-e,cnt);
		if(f[m[j].t][op]<nowmax.first)
		{
			f[m[j].t][op]=nowmax.first;
			g[m[j].t][op]=nowmax.second;
		}
		else if(f[m[j].t][op]==nowmax.first) g[m[j].t][op]+=nowmax.second;
	}
	for(int i=l,j=mid+1;j<=r;j++)
	while(i<=mid&&m[i].h>=m[j].h) 
	{
		modify(1,1,cnt,lower_bound(e+1,e+cnt+1,m[i].v)-e,i,op,0);
		//还原 
		i++;
	}
	sort(m+mid+1,m+r+1,cmp1);//这个排序别忘了 
	CDQ(mid+1,r,op);
	sort(m+l,m+r+1,cmp1);//这个排序也别忘了 
}
int main() 
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&m[i].h,&m[i].v);
		m[i].t=i;
		v[i]=m[i].v;
	}
	sort(v+1,v+n+1);
	for(int i=1;i<=n;i++)
	if(v[i]!=v[i-1]) e[++cnt]=v[i];
	OP=0;
	CDQ(1,n,0);
	for(int i=1;i<=n;i++) m[i].h=-m[i].h,m[i].v=-m[i].v;
	reverse(m+1,m+n+1);
	for(int i=1;i<=cnt;i++) e[i]=-e[i];
	sort(e+1,e+cnt+1);//上面这波操作很帅,学会 
	OP=1;
	CDQ(1,n,1);
	int maxans=-1;
	for(int i=1;i<=n;i++)
	maxans=max(maxans,f[i][0]);
	printf("%d\n",maxans);
	double sum=0;
	for(int i=1;i<=n;i++)
	if(f[i][0]==maxans) sum+=g[i][0];
	for(int i=1;i<=n;i++)
	if(f[i][0]+f[i][1]-1==maxans) printf("%.7lf ",g[i][0]/sum*g[i][1]);
	else printf("0 ");
  	return 0;
}

标签:拦截导弹,cnt,int,res1,mid,SDOI2011,1D,op
From: https://www.cnblogs.com/dingxingdi/p/18313714

相关文章

  • P2495 [SDOI2011] 消耗战
    P2495[SDOI2011]消耗战虚树优化dp模板题考虑\(m=1\)。只需要简单的树形dp,设\(f_i\)表示\(i\)子树中的关键点都到不了\(i\)点的最小代价。转移枚举子节点\(v\),有:若\(v\)点为关键点,\(f_u=f_u+w(u,v)\)。否则,\(f_u=f_u+\min(f_v,w(u,v))\)。如果每次询问都跑一遍......
  • P2487 [SDOI2011] 拦截导弹 题解
    题目链接:拦截导弹约定:本题中提到的\(LDS\)和\(LIS\)不是严格单调,而是非严格单调,即为\(\le或者\ge\)。比较神奇的题,问的东西比较多,我们逐渐拆分:对于第一个问题而言,这个dp方程是很好写的:\[dp[i]=\max{dp[j]}+1(i<j,h[i]\leh[j],v[i]\lev[j])\]其中\(dp[i]\)即......
  • P2495 [SDOI2011] 消耗战
    题意给定一棵有边权的无根树。\(q\)次询问,每次询问\(k\)个点。求断边使得根节点\(1\)与\(k\)个点不连通的最小边权。Sol虚树。\(n^2\)dp是trivial的。考虑优化。注意到其中很多点都是无用的。考虑保留有效点。不难发现,有效点集为询问点两两\(lca\)的集合......
  • P2486 [SDOI2011] 染色
    题目描述给定一棵\(n\)个节点的无根树,共有\(m\)个操作,操作分为两种:将节点\(a\)到节点\(b\)的路径上的所有点(包括\(a\)和\(b\))都染成颜色\(c\)。询问节点\(a\)到节点\(b\)的路径上的颜色段数量。颜色段的定义是极长的连续相同颜色被认为是一段。例如112221......
  • 解题报告P2486 [SDOI2011] 染色
    P2486[SDOI2011]染色题目链接分两段,最后靠同一条重链合树剖加线段树,典中典。这题的线段树维护比较新颖。线段树中维护这个区间左右端点的颜色和颜色段数量。建树和查询和修改时要判断左区间的右端点和右区间的左端点是否颜色相同。如果不相同,直接将段数相加,否则减一。然......
  • 拦截导弹
    题目概述:有一套导弹拦截系统,其每次可以拦截的导弹高度都不能高于上一次拦截导弹的高度。现在有一些导弹飞来,问这套系统最多能够拦截多少导弹,若想拦截所有的导弹,最少需要多少套系统。解题思路:第一问就是典型的LIS模型。第二问的关键在于将某枚导弹归为哪一类下降子序列,从而使得使......
  • 「SDOI2011」 黑白棋
    绷不住了,洛谷上的dp没一个表述清楚了,一怒之下写一篇题解。注意本题解只讲dp部分。首先转化不合法的充要条件就是:设相邻两个棋子中间间隔数量为\(b\),那么对于任意非负整数\(i\)都有\((d+1)|\sum(b\&2^i)\)。其中\(\&\)是按位与运算。所以我们要计数一个有序的并且包含......
  • P2486 [SDOI2011] 染色 题解
    P2486[SDOI2011]染色神仙树剖题。题意给你一棵树,每个点都有颜色,支持下面两种操作:路径染色。路径颜色段数量查询。树剖部分我们看到树上问题,不好处理,所以想办法给他树剖搞一搞,给他转化成序列的操作。我们树剖就是正常的树剖,然后我们考虑如何维护这个颜色序列。我......
  • 「SDOI2011」计算器tj
    你被要求设计一个计算器完成以下三项任务:1.给定y、z、P,计算yzmodP的值2.给定y、z、P,计算满足xy≡z(modP)的最小非负整数x;3.给定y、z、P,计算满足yx≡z(modP)的最小非负整数x。输入第一行包含两个正整数T,K分别表示数据组数和询问类型-对于一个测试点内的所有数据,询问类......
  • P2484 [SDOI2011] 打地鼠
    题目描述2020.4.29数据更新。打地鼠是这样的一个游戏:地面上有一些地鼠洞,地鼠们会不时从洞里探出头来很短时间后又缩回洞中。玩家的目标是在地鼠伸出头时,用锤子砸其头部,砸到的地鼠越多分数也就越高。游戏中的锤子每次只能打一只地鼠,如果多只地鼠同时探出头,玩家只能通过多次挥舞......