首页 > 其他分享 >Luogu P1777 帮助 题解 [ 紫 ] [ 线性 dp ] [ 状压 dp ]

Luogu P1777 帮助 题解 [ 紫 ] [ 线性 dp ] [ 状压 dp ]

时间:2024-08-04 20:16:33浏览次数:8  
标签:本书 int 题解 状压 高度 最后 Luogu dp

帮助:大毒瘤!!!调了我2h,拍了我2h,最后没调出来,重写才AC。wdnmd。

思路

这题主要是线性 dp ,而状压 dp 只是最后在统计答案时的一个辅助。

首先定义 \(dp[i][j][k]\) 为考虑前 \(i\) 本书,已经抽出来了 \(j\) 本,最后没被抽出来的一本书是高度 \(k\) 的最小混乱度。

每次放入的书与最后一位不同的时候我们把答案 \(+1\) 。

但是这样有一个弊端,就是当我们取出一些书后,还要放回去。我们自然是要放到那些没拿出来的同高度的书里面,但是如果一种高度的书全拿出来了,我们就必须加上那些全拿出来的书的种数。

观察到书本高度只能在 \([25,32]\) 这个区间里,有 \(8\) 种高度,所以我们考虑把所有书的高度 \(-25\) 后状压。

重新定义 \(dp[i][j][k][l]\) 表示考虑前 \(i\) 本书,已经抽出来 \(j\) 本,此时没被拿出来的书的状态为 \(k\) ,放在书架里的最后一本书的类型为 \(l\) 时的最小混乱度。

于是可以分两种情况转移:

  • 对于不把这本书拿出来的情况:

\[dp[i][j][k|(a[i])][a[i]]=\min(dp[i][j][k|(a[i])][a[i]],dp[i-1][j][k][l]+(a[i]!=l)) \]

这里 \(k|(a[i])\) 的原因是要把它放进去。后面 \((a[i]!=l)\) 的原因是如果高度不同,混乱度要 \(+1\) 。

  • 对于把这本书拿出来的情况:

\[dp[i][j+1][k][l]=\min(dp[i][j+1][k][l],dp[i-1][j][k][l]) \]

在 dp 完成之后,我们最后枚举后三维,并且让最终状态 \(((st \oplus p)\&p)\) ,就可以求出书架里少了哪些书,把少的书的个数加上即可,最后求个 \(\min\) 。注意提前预处理出每个二进制数 \(1\) 的个数减小常数。

最后观察到空间开销大,并且每次转移只会用到 \(i-1\) 里的数,所以考虑滚动数组优化 dp 。
同时注意提前把不合法的情况排除掉,可以减小部分常数。

代码

#include <bits/stdc++.h>
using namespace std;
int dp[2][105][260][15],a[105],pre[260],n,m,p,ans,now=0;
void solve()
{
	ans=0x3f3f3f3f;
	memset(dp,0x3f,sizeof(dp));
	dp[0][0][0][8]=0;
	for(int i=1;i<=n;i++)
	{
		int ni=(i&1),lst=(ni^1);
		memset(dp[ni],0x3f,sizeof(dp[ni]));
		for(int j=0;j<=m;j++)
		{
			for(int k=0;k<=p;k++)
			{
				for(int l=0;l<=8;l++)
				{
					if(dp[lst][j][k][l]>=(0x3f3f3f3f/2))continue;
					dp[ni][j][(k|(1<<a[i]))][a[i]]=min(dp[ni][j][(k|(1<<a[i]))][a[i]],dp[lst][j][k][l]+(a[i]!=l));
					dp[ni][j+1][k][l]=min(dp[ni][j+1][k][l],dp[lst][j][k][l]);
				}
			}
		}
	}
	for(int i=0;i<=m;i++)
	{
		for(int j=0;j<=p;j++)
		{
			for(int k=0;k<=8;k++)
			{
				ans=min(ans,dp[(n&1)][i][j][k]+pre[(j^p)&p]);
			}
		}
	}
	printf("Case %d: %d\n\n",now,ans);
}
int main()
{
	for(int i=0;i<(1<<8);i++)
	{
		for(int j=0;j<8;j++)
		{
			pre[i]+=((i>>j)&1);
		}
	}
	while(1)
	{
		now++;
		scanf("%d %d",&n,&m);
		if(n==0&&m==0)break;
		p=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			a[i]-=25;
			p=(p|(1<<a[i]));
		}
		solve();
	}
	return 0;
}

标签:本书,int,题解,状压,高度,最后,Luogu,dp
From: https://www.cnblogs.com/zhr0102/p/18341635

相关文章

  • Luogu P10842 Piggy and Trees 题解 [ 绿 ] [ 拆边 ] [ 贡献思维 ]
    PiggyandTrees:把路径拆成边的思维题。思路一看到这题的路径,就想到了LuoguP3177树上染色这题化路径为边的贡献,分别计算的思维。那么对于此题,先来观察题目里式子的意思:对于树上的每个无序点对,求出树上每个点到这些点对之间的最短路径的距离之和。枚举点对对应的就是前两......
  • 简析传输层协议——TCP、UDP协议
    TCP/IP协议族的传输层协议TCP(TransmissionControlProtocol)传输控制协议UDP(UserDatagramProtocol)用户数据报协议TCP协议介绍:TCP是面向连接的、可靠的进程到进程通信的协议TCP提供全双工服务,即数据可在同一时间双向传输TCP报文段:TCP将若干个字节构成一个分......
  • 【面试题解答】一个有序数组 nums ,原地删除重复出现的元素
    面试题解答仅供学习文章目录面试题解答题目一、python代码1.1代码1.2示例用法1.2.1示例11.2.2示例2二、讲解2.1初始化2.2遍历2.3返回题目要解决这个问题,可以使用双指针方法进行原地修改,以确保每个元素最多出现两次。一、python代码1.1代码defr......
  • 2024梦熊BeiJing集训题目题解目录
    Day1基础动态规划luoguP1896[SCOI2005]互不侵犯codeforces1209ERotateColumns(easy)codeforces1209ERotateColumns(hard)杂题luoguP2371[国家集训队]墨墨的等式AtCoderabc219_fCleaningRobotP3043[USACO12JAN]BovineAllianceG[ARC105C]CamelsandB......
  • Leetcode 第 135 场双周赛题解
    Leetcode第135场双周赛题解Leetcode第135场双周赛题解题目1:3222.求出硬币游戏的赢家思路代码复杂度分析题目2:3223.操作后字符串的最短长度思路代码复杂度分析题目3:3224.使差值相等的最少数组改动次数思路代码复杂度分析题目4:思路代码复杂度分析Leetcode......
  • CodeForces-808#D 题解
    思路分析分析样例1:3132原数组被分成1和32两部分,将2移到左边即可。我们设左边部分的和为\(s1\),右边为\(s2\),可以发现对于任何分割方式,只有满足\(s1\pmx=s2\mpx\)才可以继续讨论答案是否成立。推论1:由于\(x\ina\)(\(a\)为题目所给数列),因此\(|\s1-s2......
  • 洛谷 统计天数 + 语句解析 题解
    题目:P1567统计天数P1597语句解析第一道:P1567统计天数题目描述炎热的夏日,KC非常的不爽。他宁可忍受北极的寒冷,也不愿忍受厦门的夏天。最近,他开始研究天气的变化。他希望用研究的结果预测未来的天气。经历千辛万苦,他收集了连续 N(1≤N≤10^6)天的最高气温数据。现在......
  • DP
    1)数位DP数位DP:用来解决一类特定问题,这种问题比较好辨认,一般具有这几个特征:要求统计满足一定条件的数的数量(即,最终目的为计数);这些条件经过转化后可以使用「数位」的思想去理解和判断;输入会提供一个数字区间(有时也只提供上界)来作为统计的限制;上界很大(比如10^{18}),暴力枚举......
  • AGC064B 题解
    设红色的点值为0,蓝色为1。注意到,如果有一条边的颜色和两端点同色,一定可以选。例子:选择和两端点同色的边。又发现,如果存在一个\(sz>1\)的合法连通块,无论和其他点怎么连,原来的这个连通块内的点一定合法。有注意到形如\(0\xleftrightarrow10,1\xleftrightarrow01\)类......
  • P9351 题解
    P9351思路观察到一次覆盖操作相当于\((u,v)\)向\((u,v)\)为中心的一个矩形挖去四个角中每个点连代价为\(1\)的边。因为\(r\lec\),\(r\le\sqrt{rc}\)。暴力是01bfs,到每个点处理覆盖操作时枚举行一边,用\(n\)个并查集维护每行没有被删去的后继。对于每个点需要枚举\(......