题解 P2497 [SDOI2012]基站建设

解题思路

CDQ优化DP

下文中 \(pos_i\) 表示编号为 \(i\) 的位置或者说坐标。

暴力 DP 转移方程是 \(f_i=\min\limits_{1\le j<i}\{f_j+\dfrac{pos_i-pos_j}{2\sqrt{r_j}}\}+val_i\)

这样直接转移是 \(\mathcal{O}(n^2)\) 的,时间无法接受,尝试优化一下柿子。

对于 \(r_j>r_k\) 并且 \(j\) 优于 \(k\) 的条件就是:

\[f_j+\dfrac{pos_i-pos_j}{2\sqrt{r_j}}<f_k+\dfrac{pos_i-pos_k}{2\sqrt{r_k}} \]

\[2\times \sqrt{r_jr_k}(f_j-f_k)<-pos_i\sqrt{r_k}+pos_j\sqrt{r_k}+pos_i\sqrt{r_j}-pos_k\sqrt{r_j} \]

\[pos_i(\sqrt{r_j}-\sqrt{r_k})>2\sqrt{r_jr_k}(f_j-f_k)-pos_j\sqrt{r_k}+pos_k\sqrt{r_j} \]

\[-pos_i<\dfrac{(2\times f_j-\frac{pos_j}{\sqrt{r_j}})-(2\times f_k-\frac{pos_k}{\sqrt{r_k}})}{\frac{1}{\sqrt{r_j}}-\frac{1}{\sqrt{r_k}}} \]

然后我们就可以让 x 轴表示 \(\dfrac{1}{\sqrt{r_i}}\) y 轴表示 \(2\times f_i-\dfrac{pos_i}{\sqrt{r_i}}\)

由于 \(pos\) 具有单调性,因此我们只需要 CDQ ,并且对于左区间以 \(r\) 为关键字进行排序,单调队列维护就好了。

对于每一个 \(\dfrac{1}{\sqrt{r}}\) 可以预处理,时间复杂度: \(\mathcal{O}{nlog^2n}\),好像无法用归并排序减去一个 \(log\)

注意变量的类型不然就会 100pts -> 17pts。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Failed"<<endl
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int N=5e5+10,INF=2e18;
int n,m,q[N],pos[N];
double f[N],ans=INF,c[N];
struct Node{int pos,r,val,id;double c;}s[N];
bool comp(Node x,Node y){return x.r<y.r;}
double g(int x){return 2.0*f[x]-(1.0*pos[x])*c[x];}
void CDQ(int l,int r)
{
	if(l==r) return ;
	int mid=(l+r)>>1,head=1,tail=0; CDQ(l,mid);
	sort(s+l,s+mid+1,comp);//对于左区间进行排序
	for(int i=l;i<=mid;i++)//单调队列处理左区间可能的答案
	{
		while(head<tail&&(g(s[i].id)-g(s[q[tail]].id))*(s[q[tail]].c-s[q[tail-1]].c)>=(g(s[q[tail]].id)-g(s[q[tail-1]].id))*(s[i].c-s[q[tail]].c)) tail--;
		q[++tail]=i;
	}
	for(int i=mid+1;i<=r;i++)//处理右区间答案
	{
		while(head<tail&&g(s[q[head+1]].id)-g(s[q[head]].id)<-s[i].pos*(s[q[head+1]].c-s[q[head]].c)) head++;
		f[s[i].id]=min(f[s[i].id],(f[s[q[head]].id]+(1.0*s[i].pos-1.0*s[q[head]].pos)*s[q[head]].c/2.0)+s[i].val);
	}
	CDQ(mid+1,r);
}
signed main()
{
	n=read(); m=read();
	for(int i=1,r,val;i<=n;i++)
	{
		pos[i]=read(); r=read(); val=read(); f[i]=INF;
		if(!r){i--;n--;continue;}
		s[i]=(Node){pos[i],r,val,i,1.0/sqrt(r)}; c[i]=1.0/sqrt(r);
	}
	f[1]=s[1].val; CDQ(1,n);
	for(int i=1;i<=n;i++)
		if(s[i].pos+s[i].r>=m)
			ans=min(ans,f[s[i].id]);//计算答案
	printf("%.3lf",ans);
	return 0;
}
posted @ 2021-09-24 21:10  Varuxn  阅读(117)  评论(0编辑  收藏  举报