首页 > 其他分享 > To_Heart—总结——连通块 dp(抑或 连续块 dp)

To_Heart—总结——连通块 dp(抑或 连续块 dp)

时间:2023-11-10 22:56:53浏览次数:34  
标签:Heart 连通 int ll now dp Mod

简介

有一类问题,他们需要计算满足在序列上插入给定顺序的元素,其贡献/限制只与两旁的元素有关,但元素插入的位置是不一定的,所以会有代价的最值和方案数的统计。而对于这类问题,我们其实可以不关心每一次插入的具体位置在哪里,而只关注他的相对位置(比如在某个数左边、在某个数左边且与其相邻之类的),从而将状态大大简化。

模型

通常以二维表示 dp[i][j] 表示插入到第 i 个元素,前 i-1 个元素已经插入到序列上,一共形成了 j 个连通块的 方案数/代价。转移有三种大类,分别是合并两个连通块、新加一个连通块、延续一个连通块。

考虑为什么要用连通块表示 相对位置的信息。因为连通块可以表示左右是否有数、以及左右的数是否与其相邻。这里面有个隐藏的参数是当前场上的元素数量,但我们发现用 i 就表示完了。

纸上觉来终觉浅,下面进入实战。

题目讲解

1.摩天大楼

首先注意到限制有绝对值,考虑将 a[i] 按照从大到小的顺序插入到序列中,那么绝对值的限制就去掉了。我们发现此时插入的元素顺序确定,并且发现当前插入一个数的代价与其它已经在序列上的数有关,符合模型,即可使用 连通块dp 解决。细节交给读者思考。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const ll Mod=1e9+7;

int n,L;
int a[105];
ll dp[105][105][1005][2][2];
//int now[105][105][1005][2][2];

bool cmp(int x,int y){ return x>y; }

int main(){
	cin>>n>>L;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	sort(a+1,a+n+1,cmp);
	dp[1][1][0][0][0]=dp[1][1][0][1][1]=dp[1][1][0][0][1]=dp[1][1][0][1][0]=1;
	for(int i=2;i<=n;i++){
		for(int j=1;j<i;j++) for(int k=0;k<=L;k++) for(int p=0;p<=1;p++) for(int q=0;q<=1;q++) if(dp[i-1][j][k][p][q]){
			int now=(a[i-1]-a[i])*(j*2-p-q);
			if(k+now>L) continue;
			if(j>1) dp[i][j-1][k+now][p][q]+=dp[i-1][j][k][p][q]*(j-1),dp[i][j-1][k+now][p][q]%=Mod;
			if(j>1) dp[i][j+1][k+now][p][q]+=dp[i-1][j][k][p][q]*(j-1),dp[i][j+1][k+now][p][q]%=Mod;
			if(j>1) dp[i][j][k+now][p][q]+=dp[i-1][j][k][p][q]*(2*j-2),dp[i][j][k+now][p][q]%=Mod; 
			if(!p){
				dp[i][j][k+now][1][q]+=dp[i-1][j][k][p][q],dp[i][j][k+now][1][q]%=Mod; 
				dp[i][j][k+now][0][q]+=dp[i-1][j][k][p][q],dp[i][j][k+now][0][q]%=Mod;
				dp[i][j+1][k+now][1][q]+=dp[i-1][j][k][p][q],dp[i][j+1][k+now][1][q]%=Mod; 
				dp[i][j+1][k+now][0][q]+=dp[i-1][j][k][p][q],dp[i][j+1][k+now][0][q]%=Mod;
			}
			if(!q){
				dp[i][j][k+now][p][1]+=dp[i-1][j][k][p][q],dp[i][j][k+now][p][1]%=Mod; 
				dp[i][j][k+now][p][0]+=dp[i-1][j][k][p][q],dp[i][j][k+now][p][0]%=Mod;
				dp[i][j+1][k+now][p][1]+=dp[i-1][j][k][p][q],dp[i][j+1][k+now][p][1]%=Mod;
				dp[i][j+1][k+now][p][0]+=dp[i-1][j][k][p][q],dp[i][j+1][k+now][p][0]%=Mod;
			}
		}
	}
	ll ans=0;
	for(int i=0;i<=L;i++) ans+=dp[n][1][i][1][1],ans%=Mod;
	cout<<ans<<endl;
	return 0;
}

2.P5999

题解看了好久没看懂,u群问了一个多小时,这下听懂了。对于这类问题我们转换一下,改为往操作序列上面依次放第 i 个草丛。注意到第 s 个草丛和第 t 个草丛在操作序列上的相对位置也需要特判。

你们他妈注意了,第一步转换很重要!!!非常重要!!!!这才是能在 i==s||i==t 特判的原因!!!!

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll Mod=1e9+7;

ll dp[2005][2005];
int n,s,t;

int main(){
	cin>>n>>s>>t;
	dp[1][1]=1;
	for(int i=2;i<=n;i++) for(int j=1;j<=i;j++){
		if(i==s||i==t) dp[i][j]=dp[i-1][j-1]+dp[i-1][j],dp[i][j]%=Mod;
		else dp[i][j]=dp[i-1][j-1]*(j-(i>s)-(i>t))%Mod+dp[i-1][j+1]*j%Mod;	
	}
	cout<<dp[n][1]<<endl;
	return 0;
}

标签:Heart,连通,int,ll,now,dp,Mod
From: https://www.cnblogs.com/xf2056188203/p/17825240.html

相关文章

  • 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\)种操作序列。从前往后将所有的操作序列归并到全局的操作序列里,拿组合数随便乱搞搞就好了。代码......
  • 20231108数数与dp题笔记
    数数与dpCF294CShaassandLights记被分成的\(m+1\)段每一段的长度为\(l_i\)答案为\[\frac{(n-m)!}{\prod\limits_{i=1}^{m+1}l_i!}\times\prod\limits_{i=1}^{m+1}2^{l_i-1}\]前面是不同段之间的顺序打乱,后面是每一段中前\(l_i-1\)个操作各有\(2\)个选择CF1753CW......
  • .NET 8 IEndpointRouteBuilder详解
    Map​ 经过对WebApplication的初步剖析,我们已经大致对Web应用的骨架有了一定了解,现在我们来看一下HelloWorld案例中仅剩的一条代码:app.MapGet("/",()=>"HelloWorld!");//3添加路由处理​ 老规矩,看签名:publicstaticRouteHandlerBuilderMapGet(thisIEndpointRout......
  • SP15637 GNYR04H - Mr Youngs Picture Permutations(线性 dp)
    题目求方案数,考虑dp——状态设计和边界——题目告诉了一个很显然的性质:每一排从左至右保证高度单调递减每一列从后往前保证高度单调递减那么可以发现,对于每一行,每一列,一定是按高度顺序插入,并且是连续插入,因为如果不连续,就无法保证单调递减的性质同时,它给出了另一个性......
  • P2196-DP【黄】
    清醒了一点后我又写了一道黄色DP题,做出来了,还行,开心不少了...中途暴露出一些问题1、深搜过程中既然用了二维数组,那么深搜时就应该用二维循环取最优解,而不是只从最后一行中进行一维循环取最优解。2、dfs递归的过程中应该用dfs!!!不应该像个智障一样的忘了用dfs,直接用dp数组忘了递归......