新坑,持续更新,动归专题(普通Dp)

目的是改名emm,我看我要写多久


1.消除游戏

消除游戏
考点: 记忆化搜索,合并操作。(这道题的合并操作是值得学习的!!!)
在这里插入图片描述
代码:

int Dfs(int From,int To,int p)
{
	if (f[From][To][p]!=inf) return f[From][To][p];
	if (From>To) return 0;  
	if (From==To) return m-p-1;
	int tmp=inf;
	if (p==m-1) tmp=min(tmp,Dfs(From+1,To,0));
	else tmp=min(tmp,Dfs(From,To,p+1)+1);
	for (int i=From+1;i<=To;i++)
	if (a[i]==a[From]) tmp=min(tmp,Dfs(From+1,i-1,0)+Dfs(i,To,min(p+1,m-1)));
	return f[From][To][p]=tmp;
}
  • 如果将状态中的p放在 [ i , j ] [i,j] [i,j]里面是否好做?

2.草地排水

题目大意: 给你一些带权线段,数量为 n n n,左端点为 a i a_i ai,右端点为 b i b_i bi,权值是 c i c_i ci。每条线段只有一次选择机会,没有选择限制。求在线段不重复的前提下,能得到的最大值。
在这里插入图片描述
考点: 离散化(unique用完要 -1!!!),最大值维护(我用的是单调队列,但是这里也可以用树状数组维护。听了评讲才知道原来两个都可以不用emm)

代码

int t=unique(a+1,a+1+cnt)-a-1;//考场上没有-1死于非命QAQ

for (int i=1;i<=t;i++)
	{
		if (v[i].size())
		{
			ll tmp=f[q.front()];
			for (int j=0;j<v[i].size();j++) 
			f[v[i][j].To]=max(f[v[i][j].To],tmp+v[i][j].Cost);
		}
		if (mark[i])
		{
			//打一个标记,只把线段的末端统计进来,这样就避免了用别人的左端更新自己的右端情况。 
			ans=max(ans,f[i]);
			while (q.size()&&f[q.back()]<f[i]) q.pop_back();q.push_back(i);
		}//其实这样的话还有一个用处,避免交叉 
	}

3.2019.11.5集训第二题

题目大意:现在有1到n个数,第i数有上下界 [ 1 , a i ] [1,a_i] [1,ai]。现在把他们放在一个环上,使得任意相邻两个数选择的数值是不一样的。求方案数。
数据范围 n ≤ 1 0 6 , a i ≤ 1 0 9 n\leq10^6,a_i\leq10^9 n106ai109
题解
我们先把它放到上讨论:
定义状态 f i f_i fi表示讨论到第i个数的方案数。那么就有 f i = f i − 1 ∗ a i f_i=f_{i-1}*a_i fi=fi1ai
但是我们加多了,没有考虑 a i a_i ai a i − 1 a_{i-1} ai1相等的情况,重新改写式子
f i = f i − 1 ∗ a i − f i − 2 ∗ m i n ( a i , a i − 1 ) f_i=f_{i-1}*a_i-f_{i-2}*min(a_i,a_{i-1}) fi=fi1aifi2min(ai,ai1)
但是我们又减多了,没有考虑 a i − 1 a_{i-1} ai1 a i − 2 a_{i-2} ai2相等的情况,所以
f i = f i − 1 ∗ a i − [ f i − 2 ∗ m i n ( a i , a i − 1 ) − f i − 3 ∗ m i n ( a i , a i − 1 , a i − 2 ) ] f_i=f_{i-1}*a_i-[f_{i-2}*min(a_i,a_{i-1})-f_{i-3}*min(a_i,a_{i-1},a_{i-2})] fi=fi1ai[fi2min(ai,ai1)fi3min(ai,ai1,ai2)]
打开过后就是
f i = f i − 1 ∗ a i − f i − 2 ∗ m i n ( a i , a i − 1 ) + f i − 3 ∗ m i n ( a i , a i − 1 , a i − 2 ) f_i=f_{i-1}*a_i-f_{i-2}*min(a_i,a_{i-1})+f_{i-3}*min(a_i,a_{i-1},a_{i-2}) fi=fi1aifi2min(ai,ai1)+fi3min(ai,ai1,ai2)
那么我们就有:
f [ i ] = ∑ j = 0 i f [ j ] ∗ m i n ( a [ j + 1... i ] ) ∗ ( − 1 ) i + j f[i]=\sum^{i}_{j=0}{f[j]*min(a[j+1...i])*(-1)^{i+j}} f[i]=j=0if[j]min(a[j+1...i])(1)i+j
对它进行化简可以得到
f [ i ] = ( − 1 ) i ∑ j = 0 i f [ j ] ∗ m i n ( a [ j + 1... i ] ) ∗ ( − 1 ) j f[i]=(-1)^i\sum^{i}_{j=0}{f[j]*min(a[j+1...i])*(-1)^{j}} f[i]=(1)ij=0if[j]min(a[j+1...i])(1)j
现在我们来考虑在上的情况,定义 g i g_i gi表示有i个元素的环的方案数。环与链的不同在于环要考虑首尾不同的情况。所以我们只需要从链中减去最后一个等于第一个的情况就可以了。
仔细思考一下,我们能够发现,如果最后一个与第一个相同,我们把两者合并一下就变成了长度为i-1的环。所以 g i = f i − g i − 1 g_i=f_i-g_{i-1} gi=figi1
有一个小细节:我们要从环上最小的一个点开始我们的计算
原因在于,如果从较大的数开始讨论,讨论到最小的值时可能就没有数可以选择了。

考点:由环到链,由链到环;单调栈;

2019.11.13晚上的C题

今日份的大吉owo
题目大意
  现在给你一个n*m的矩阵,你需要从(1,1)走到(n,m);但是邪恶的索隆大魔王已经预测到你的行程,于是祂决定在其余的格子上派兵。由于怪物来自同一个军队,所以他们的体力是相同的,但是每个怪物由于战斗经历不同,造成的攻击也就不一样。如果你在当前方格碰上了他们,除非当前格子的怪物死去,否则你是不能通过的。
  不过好在智慧的灰袍甘道夫在你临行前送了你两份法宝——一把魔法手杖!以及无限体力药水。魔法手杖的攻击力是一定的,你可以用它攻击你当前所在格子的怪物,为了方便讨论。我们把它设计成回合制战斗,保证你是先手。虽然你有魔法药水,但是受到伤害还是会觉得很痛,所以你希望到达终点时受到的伤害尽可能的少。
  为了让这道题更有趣一些,魔法手杖进化出了特殊技能——使用该技能会使你接下来 s次移动,每一次移动后增加等同于移动到的格子的怪物的攻击力,s 次移动后,魔法手杖攻击力恢复至初始攻击力。但是有使用限制,而且必须要等上一个技能使用完,再使用下一个(不然就太没有意思啦)

数据范围
1 ≤ n , m ≤ 500 , 1 ≤ t ≤ 10 , 1 ≤ k ≤ 5 1\leq n,m\leq500,1\leq t\leq10,1\leq k\leq5 1n,m500,1t10,1k5
1 ≤ a t k ≤ 100 , 1 ≤ 1\leq atk\leq100,1\leq 1atk100,1 怪物攻击力 ≤ 100 \leq100 100

思路部分
  不用思索就知道是多维Dp,先定状态 f [ i ] [ j ] [ k ] [ t ] [ s ] [ m ] f[i][j][k][t][s][m] f[i][j][k][t][s][m]表示当前在 ( i , j ) (i,j) (i,j)位置,还剩下 k k k次技能可以使用,并且当前的攻击力是 m m m。剩下的 t t t表示在技能状态下,还剩下 t t t步可走,而 s s s就表示是否在技能状态。
  然后我们算一算空间,完了,爆炸了。于是就选择睿智的观察数据范围,发现每次使用技能后能移动的步数很小。于是果断来DFS

void Dfs(int x,int y,int k,int g,int s,int ti)
{
	x,y表示当前所在位置。k表示还剩下的技能次数,g表示当前攻击力。
	s表示还剩下的步数,ti表示当前受到的伤害值。
	if (x>n||y>m) return ; 
	攻击力+=Map[x][y]; 伤害值+=tmp*Map[x][y];伤害增加up!up!
	if (x==n&&y==m) 讨论在技能状态下跑到终点的情况
	if (s==1) 如果步数走到尽头
	Dfs(x+1,y,k,g,s-1,ti);
	Dfs(x,y+1,k,g,s-1,ti);
}

那么转移方程就只用考虑三个维度就可以啦
设定状态f [ i ] [ j ] [ k ] [i][j][k] [i][j][k]表示当前位于 ( i , j ) (i,j) (i,j)位置,还剩下 k k k次技能可以使用。由于不好由过去转移过来,我们就想想往未来转移。

f[i+1][j][k]=min(f[i+1][j][k],f[i][j][k]);
f[i][j+1][k]=min(f[i][j+1][k],f[i][j][k]);

然后注意一下算伤害时的细节

写在DFS函数中的
f[x][y][k]=min(f[x][y][k],ti-cnt*Map[x][y]);
写在主函数循环中的
f[i][j][k]=f[i][j][k]+cnt*Map[i][j];

然后就做完啦

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值