首页 > 其他分享 >P9550 「PHOI-1」晚宴筵题解

P9550 「PHOI-1」晚宴筵题解

时间:2024-01-26 23:55:20浏览次数:36  
标签:le r1 val P9550 题解 int text PHOI dp

image

题解

简化一下题意,已知从 \((p,q)\) 直接到达 \((x,y)\) 的费用函数如下:

\[\text{cost}(p,q,x,y) = \begin{cases} w_p+w_q+w_x+w_y-p-q-x-y, & l1_x \le p \le r1_x,l2_y \le q \le r2_y \\ \text{inf}, & \text{otherwise} \\ \end{cases}\]

问从 \((1,1)\) 到各位置的最小费用。

如果暴力建图跑最短路,由于 \(n\) 可以达到 \(\text{1e3}\),一共有 \(n^2\) 个点,边更多,肯定爆炸。

不妨思考是否有 \(\text{DP}\) 的做法,如果设 \(dp_{i,j}\) 表示 \((1,1)\) 到 \((i,j)\) 的最小费用,则有:

\[dp_{x,y}=\min_{l1_x \le p \le r1_x,l2_y \le q \le r2_y}{(dp_{p,q}+\text{cost}(p,q,x,y))} \]

注意到,\(r1_x<x\),\(r2_y<y\),显然满足无后效性,可以 \(\text{DP}\),但是暴力是 \(n^4\) 的,仍然超时。

将方程抽象成矩阵问题,有一个 \((n+1) \times (n+1)\) 的矩阵,因为有 0。每个位置 \((i,j)\) 有一个权值表示 \(dp_{i,j}+w_i+w_j-i-j\)。那么在求解 \((x,y)\) 时,相当于在一个子矩阵中求出最小权值 \(\text{Pre}\),然后让 \(dp_{x,y}=\text{Pre}+w_x+w_y-x-y\),接着修改 \((x,y)\) 处的数值为 \(dp_{x,y}+w_x+w_y-x-y\)。

也就是要维护子矩阵极值,单点修改。我们可以用 \(1\) 个线段树维护行,线段树的每个结点上维护一个线段树来维护列。即线段树套线段树,容易证明,单次操作是 \(O(\log^2 n)\) 的。总体的时间复杂度就是 \(O(n^2\log^2 n)\) 可以接受。

代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
const int inf=1e9;
int n,l1[N],r1[N],l2[N],r2[N],w[N]; 
int dp[N][N],Pre;
struct node_y {
	int l,r,val;
};
struct tree_y {
	node_y tr[N<<2];
	void pushup(int p) {
		tr[p].val=min(tr[p<<1].val,tr[p<<1|1].val);
	}
	void build(int p,int l,int r) {
		tr[p].l=l,tr[p].r=r;
		if(l==r) {
			tr[p].val=inf;
			return;
		}
		int mid=l+r>>1;
		build(p<<1,l,mid);
		build(p<<1|1,mid+1,r);
		pushup(p);
	}
	void update(int p,int y,int k) {
		if(tr[p].l==tr[p].r) {
			tr[p].val=min(tr[p].val,k);
			return;
		}
		int mid=(tr[p].l+tr[p].r)>>1;
		if(y<=mid) update(p<<1,y,k);
		else update(p<<1|1,y,k);
		pushup(p);
	}
	int query(int p,int l,int r) {
		if(l<=tr[p].l&&tr[p].r<=r) return tr[p].val;
		int mid=(tr[p].l+tr[p].r)>>1;
		int val=inf;
		if(l<=mid) val=min(val,query(p<<1,l,r));
		if(r>mid) val=min(val,query(p<<1|1,l,r));
		return val;
	} 
};
struct node_x {
	int l,r;
	tree_y T;
};
struct tree_x {
	node_x tr[N<<2];
	void build(int p,int l,int r) {
		tr[p].l=l,tr[p].r=r;
		tr[p].T.build(1,1,n+1);
		if(tr[p].l==tr[p].r) return;
		int mid=l+r>>1;
		build(p<<1,l,mid);
		build(p<<1|1,mid+1,r);
	}
	void update(int p,int x,int y,int k) {
		tr[p].T.update(1,y,k);
		if(tr[p].l==tr[p].r) return;
		int mid=(tr[p].l+tr[p].r)>>1;
		if(x<=mid) update(p<<1,x,y,k);
		else update(p<<1|1,x,y,k);
	}
	int query(int p,int lx,int rx,int ly,int ry) {
		if(lx<=tr[p].l&&tr[p].r<=rx) return tr[p].T.query(1,ly,ry);
		int mid=(tr[p].l+tr[p].r)>>1;
		int val=inf;
		if(lx<=mid) val=min(val,query(p<<1,lx,rx,ly,ry));
		if(rx>mid) val=min(val,query(p<<1|1,lx,rx,ly,ry));
		return val;
	}
};
tree_x A;
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>l1[i];
	for(int i=1;i<=n;i++) cin>>r1[i];
	for(int i=1;i<=n;i++) cin>>l2[i];
	for(int i=1;i<=n;i++) cin>>r2[i];
	for(int i=1;i<=n;i++) cin>>w[i];
	A.build(1,1,n+1);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++) dp[i][j]=inf;
	dp[1][1]=0;
	A.update(1,2,2,2*w[1]-2);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++) {
			if(i==1&&j==1) continue;
			Pre=inf;
			Pre=min(Pre,A.query(1,l1[i]+1,r1[i]+1,l2[j]+1,r2[j]+1));
			if(Pre!=inf) {
				dp[i][j]=Pre+w[i]+w[j]-i-j;
				A.update(1,i+1,j+1,dp[i][j]+w[i]+w[j]-i-j);
			}
		}
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=n;j++) {
			if(dp[i][j]==inf) cout<<"inf ";
			else cout<<dp[i][j]<<" ";
		}
		cout<<endl;
	}
	return 0;
}

标签:le,r1,val,P9550,题解,int,text,PHOI,dp
From: https://www.cnblogs.com/2021hych/p/17990965

相关文章

  • P2602 数字计数 题解
    QuestionP2602数字计数求\([a,b]\)中的所有整数中,每个数出现的次数Solution数位DP板子题定义\(dp[i]\)表示\(i\)位数的每种数字有多少个,我们把\(0\)和\(00\)看成两种不同的数,并且\(00\)中算\(0\)出现过两次显然,\(0\sim9\)在\(i\)位数中出现的次数是一样......
  • 洛谷题解-P2712 摄像头
    https://www.luogu.com.cn/problem/P2712可以看出是拓扑排序,因为是有前后关系的,但是坑点在于点并不连续,值得记录一下(刚开始70分,后来才AC)注意坑点:拓扑排序,遍历的点不连续 #include<bits/stdc++.h>usingnamespacestd;constintN=1e5+5;intn,x,m,y,d[N],cnt=0,v......
  • markdown图床问题解决
    写博客不仅要以文字形式记录,更重要的是把自己曾经的截图记录下来,更方便下次使用。所以有必要搞一个稳定的图床生成图片链接。一开始我是用的Github,新建一个仓库上传图片,优点是方便,缺点是网络不用魔法图片经常加载不出来。后来看到网上一些博主推荐使用七牛云图片存储,为此我购买......
  • CF1654G Snowy Mountain 题解
    题目链接点击打开链接题目解法很牛的题显然可以\(O(n)\)多源\(bfs\)求出\(h_i\)考虑从\(st\)开始最优的操作是什么?先延最短路径到\(p\),然后找到\(p\)的相邻点\(q\),满足\(h_p=h_q\),在\(p,q\)之间横跳,耗完所有动能,然后直接滑下去(不经过高度相同的点)为什么到\(p......
  • [西湖论剑 2022]web部分题解(更新中ing
    [西湖论剑2022]NodeMagicalLogin环境!启动!(ノへ ̄、)这么一看好像弱口令啊,(不过西湖论剑题目怎么会这么简单,当时真的傻),那就bp抓包试一下(这里就不展示了,因为是展示自己思路,这里就写了一下当时的NC思路,其实是不对的┭┮﹏┭┮)不是BP弱口令?那好吧,我们先看一下源码,比赛的时候是给了源......
  • Altair SimSolid常见问题解答 衡祖仿真
    Q:SimSolid究竟有什么特别之处?A:AltairSimSolid是专为设计工程师开发的结构分析软件且非常有创新性。它消除了传统FEA中特别耗时和非常专业的两项庞大任务——几何结构简化和网格划分,是一场仿真变革。简而言之,就是不用做几何简化,不用画网格,复杂装配体数量没有上限,真实三维模型直......
  • 蓝牙BQB认证申请过程常见问题解答
    BQB全名:BluetoothQualificationBody,我们一般称之为蓝牙资格认证,产品具有蓝牙功能并且在产品外观上标明蓝牙标志(Bluetoothlogo),必须通过蓝牙BQB的认证。1、为什么要过BQB?蓝牙技术联盟(BluetoothSpecialInterestGroup,简称SIG),蓝牙技术是它发明的。我们要使用它的专利,必须拿......
  • CF1515F Phoenix and Earthquake 题解
    题目链接:CF或者洛谷首先基于一个事实,答案一定是生成树,显然,每次我们都需要连边,每次都会\(-x\),那么一共会减少\((n-1)\timesx\),很显然的一个必要条件为:\[\sum_{i=1}^{n}a_i\ge(n-1)\timesx\显然一定成立。\]现在我们用来证明它同时也是一个充分条件,不妨设:\[a_1\lea......
  • latex常见问题解决
    1.Fileendedwhilescanninguseof\@writefile解决方法:删除编译文件夹内.aux扩展名结尾的文件,重新用Latex命令进行编译,自动生成正确的aux文件,完成错误的修复。注:如果还不好使,就把除.tex以外的文件均删除掉,如:.bbl,.blg,.dvi,.log等2.多行缩进ctrl+a全选后,shift+tab向前退......
  • [Bzoj 3252] 攻略 题解
    攻略题面\(n(\le2\cdot10^5)\)个点的有根树,\(k(\len)\)次从根走到叶子,每个点有权值,求经过的点的权值和的最大值.(同一个点只能算一次)Sol1我们设想一个叶子一个叶子加进去的过程。如果有两个从某个点到叶子的路径,我们可以如图把他分成两条路径。那么他满足贪心,也就是每次......