首页 > 其他分享 >P3842-DP【黄】

P3842-DP【黄】

时间:2023-11-11 16:33:55浏览次数:24  
标签:P3842 int dp ANS include col DP row

想搜索到最后一层,就必得先完成前面层的搜索任务,这构成了对状态转移的启示,即当前层的DP值应该是此前层转移过来后得到的最佳值。
但这道题看数据范围应该不能用二维数组,抱着侥幸的心理我使用了动态二维数组,dpij表示以第i层第j个为终点时的答案,结果MLE了,喜提42分,详见CODE-1。

后来意识到(其实是瞥了一眼题解后立刻受启发,然后想到的...)从中间节点转移过去是等价于先从边界节点动到中间节点在下去移动的,换句话说不需要存储、记录、判断那么多的状态,只需要存2*n个值就可以,但好像我写假了,不知为什么只有七十多分,详见CODE-2

总结,用记搜思想或者“想搜索到最后一层,就必得先完成前面层的搜索任务”等方法判断出所需的DP的下标的含义,然后在写出状态转移方程,这是我自己归纳的思考DP问题的一种比较简单的思维路径,应该多用用

CODE-1

#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <stack>
#include <queue>
#include <map>
#include <unordered_map>
#include <cmath>
//#define int long long
using namespace std;

int * dp[20000+2];
int n,L[20000+2],R[20000+2];
int dfs(int row,int col)
{
	if(col<L[row]||col>R[row])return 0;
	if(dp[row][col-L[row]]!=-1)return dp[row][col-L[row]];
	if(row==1)return dp[row][col-L[row]]=R[row]-1+R[row]-col;
	int ANS=99999999;
	for(int i=L[row-1];i<=R[row-1];i++)
	{
		if(i<=R[row]&&i>=L[row])
			ANS=min(ANS,dfs(row-1,i)+1+2*(R[row]-max(i,col))+2*(min(i,col)-L[row])+max(i,col)-min(i,col));
		else if(i>R[row]) ANS=min(ANS,dfs(row-1,i)+1+i-L[row]+col-L[row]);
		else if(i<L[row]) ANS=min(ANS,dfs(row-1,i)+1+R[row]-i+R[row]-col);
	}
	return dp[row][col-L[row]]=ANS;
}
signed main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>L[i]>>R[i];
		dp[i]=new int[R[i]-L[i]+1];
		for(int j=0;j<R[i]-L[i]+1;j++)dp[i][j]=-1;//li~ri->0~ri-li
	}
	cout<<n-R[n]+dfs(n,R[n])<<endl;
	return 0;
}
	/*
	dfs(n,R[n]);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			printf("%3d",dfs(i,j));
		}
		cout<<endl;
	}*/

CODE-2

#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <stack>
#include <queue>
#include <map>
#include <unordered_map>
#include <cmath>
#define int long long
using namespace std;

int dp[20000+2][3];
int n,L[20000+2],R[20000+2];
int dfs(int row,int col)//now col is left or right
{
	if(dp[row][col]!=-1)return dp[row][col];
	int ANS=1e16;

	if(col==1)//towards L[row]
	{
		//from L[row-1]
		if(L[row-1]<=R[row])
			ANS=min(ANS,dfs(row-1,1)+1+R[row]-L[row-1]+R[row]-L[row]);
		else 
			ANS=min(ANS,dfs(row-1,1)+1+L[row-1]-L[row]);
		//from R[row-1]
		if(R[row-1]<=R[row])
			ANS=min(ANS,dfs(row-1,2)+1+R[row]-R[row-1]+R[row]-L[row]);
		else 
			ANS=min(ANS,dfs(row-1,2)+1+R[row-1]-L[row]);
	}
	else//towards R[row]
	{
		//from L[row-1]
		if(L[row-1]<=L[row])
			ANS=min(ANS,dfs(row-1,1)+1+R[row]-L[row-1]);
		else 
			ANS=min(ANS,dfs(row-1,1)+1+L[row-1]-L[row]+R[row]-L[row]);
		//from R[row-1]
		if(R[row-1]<=L[row])
			ANS=min(ANS,dfs(row-1,2)+1+R[row]-R[row-1]);
		else 
			ANS=min(ANS,dfs(row-1,2)+1+R[row-1]-L[row]+R[row]-L[row]);
	}
	for(int i=L[row-1];i<=R[row-1]/2;i++)
	{
		
		if(i<=R[row]&&i>=L[row])
			ANS=min(ANS,dfs(row-1,2)+R[row-1]-i+1+2*(R[row]-max(i,col))+2*(min(i,col)-L[row])+max(i,col)-min(i,col));
		else if(i>R[row]) ANS=min(ANS,dfs(row-1,2)+1+i-L[row]+col-L[row]);
		else if(i<L[row]) ANS=min(ANS,dfs(row-1,2)+1+R[row]-i+R[row]-col);
	}
		
	return dp[row][col]=ANS;
}
signed main()
{
	scanf("%ld",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%ld%ld",&L[i],&R[i]);
		for(int j=0;j<3;j++)dp[i][j]=-1;//li~ri->0~ri-li
	}
	dp[1][1]=R[1]-1+R[1]-L[1];
	dp[1][2]=R[1]-1;
	cout<<min(n-R[n]+dfs(n,2),n-L[n]+dfs(n,1))<<endl;
	return 0;
}
	/*
	dfs(n,R[n]);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			printf("%3d",dfs(i,j));
		}
		cout<<endl;
	}*/

标签:P3842,int,dp,ANS,include,col,DP,row
From: https://www.cnblogs.com/gongkai/p/17826029.html

相关文章

  • 状态机模型DP
    //http://ybt.ssoier.cn:8088/problem_show.php?pid=1302#include<bits/stdc++.h>usingnamespacestd;constintN=2e5+10;intdp[N][3][3],n,w[N],t;intmain(){cin>>t;while(t--){cin>>n;intres=0;memset(......
  • [题解] AT_dp_w Intervals
    Intervals有\(m\)条形如\((l,r,a)\)的限制,表示如果\(s_{[l,r]}\)中有1就会有\(a\)的价值。你要求长度为\(n\)的01串的价值的最大值。\(n,m\le2\times10^5\)。将每个限制挂到右端点上,在右端点处计算贡献。然后我们就只关心最后一个1出现的位置了。......
  • 【小沐学前端】Windows下搭建WordPress(一、相关工具下载)
    1、简介WordPress是基于PHP和MySQL的免费开源内容管理系统(CMS)。它是全球使用最广泛的CMS软件,截至2019年5月,它为排名前1000万个网站中提供了超过30%的支持,并拥有在使用CMS构建的所有网站中,估计有60%的市场份额。1.1Nginxnginx[enginex]是一个HTTP和反向代理服务器,邮件代理......
  • To_Heart—总结——连通块 dp(抑或 连续块 dp)
    简介有一类问题,他们需要计算满足在序列上插入给定顺序的元素,其贡献/限制只与两旁的元素有关,但元素插入的位置是不一定的,所以会有代价的最值和方案数的统计。而对于这类问题,我们其实可以不关心每一次插入的具体位置在哪里,而只关注他的相对位置(比如在某个数左边、在某个数左边且与......
  • DP查缺补漏之LCS状态重叠
    DP查缺补漏之\(LCS\)状态重叠状态假设\(F[i][j]\)为\(a\)串中前\(i\)个字符,\(b\)串中前\(j\)个字符构成的\(LCS\)状态转移\(F[i-1][j-1]+1\)即当且仅当\(a[i]=b[j]\)时,从两个序列的减去当前的字符加一推出\(F[i-1][j]\)不选\(a[i]\),只选\(b[j]\)\(F[i......
  • Oracle ODP.NET ConnectionString接池及连接参数
      出自: https://blog.csdn.net/qq_28570965/article/details/126935639 1.连接字符串中提供了服务器地址,端口,实例等信息,具体格式如下:DataSource=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=MyHost)(PORT=MyPort))(CONNECT_DATA=(SERVICE_NAME=MyDatasource)));UserID=M......
  • DP查缺补漏之LIS状态记录
    DP查缺补漏之\(LIS\)状态记录前置知识状态假设\(F[i]\)为以\(a[i]\)为结尾的最长上升子序列长度。状态转移\(F[i]=max(F[j]+1,F[i])(j<i)\)很好理解,即\(i\)之前的所有以\(a[j]\)结尾的最长上升子序列中取最大,再加上\(a[i]\)即加一。代码实现for(inti=1;i<=......
  • MIPI/DSI转eDP新选择CS5523芯片替代LT8911EXB,IT6151
    ASL(集睿致远)CS5523是一颗MIPIDSI输入,DP/eDP输出转换芯片。MIPI输入4lanes,每lane最大支持1.5Gbps,DP/eDP输出最多支持4lanes,每条lane最大支持2.7Gbps。芯片内部有一个MCU,自带flash。功能框图:特点:MIPIDSI输入和DP/eDP输出支持抖音和6位+FRC。将PWM......
  • DP难题:颜色的长度
    颜色的长度ColorLength题面翻译输入两个长度分别是$n$和$m(n,m\leq5000)$的颜色序列,要求按顺序合并成同一个序列,即每次可以把一个序列开头的颜色放到新序列的尾部。例如,两个颜色序列GBBY和YRRGB,至少有两种合并结果:GBYBRYRGB和YRRGGBBYB。对于每种颜色来说其跨度L(c......
  • DP 与计数
    NFLSOJACF294CShaassandLight考虑初始已点亮的灯将所有剩下的灯划分成的连续段。除开头结尾外,每个长为\(l\)的连续段有\(2^l\)种操作序列。开头结尾的连续段只有\(1\)种操作序列。从前往后将所有的操作序列归并到全局的操作序列里,拿组合数随便乱搞搞就好了。代码......