BSOJ 2247 瑰丽华尔兹

这道是NOI2005的原题吧

这道题乍一看,很容易设计出状态f[T][N][M],而且鉴于T有40000,K只有200,倾斜方向也是基于K的,因此把状态设计成f[K][N][M],即第K段时间滑到(N,M)位置的最大滑行距离。

设p[K]为第K段时间的持续长度,这样的话,根据倾斜方向不同,我们得到了四种转移方程。

f[K][N][M]=max(f[K-1][i][j]+dist)(dist<=p[K])

向上时:j=M,i>=N,dist=i-N

向下时:j=M,i<=N,dist=N-i

向左时:i=N,j>=M,dist=j-M

向右时:i=N,j<=M,dist=M-j

可以把K的那一维数组滚动掉,但是我很懒,没有这样做。

问题来了,这个转移方程虽然很有效,但是直接做会超时。我们发现,每次转移事实上都是在一行或者一列上进行取最大值的操作,这一操作不优化的话复杂度是O(M)或O(N),

把这一维单独拿出来(仅以向下滑动为例,其它的类比),就是f[N]=max(f[i]+N-i)=max(f[i]-i)+N(N-i<=p[K])

这样的话就符合了单调队列优化的基本模型,队列中存的是f[i]-i,当遇到障碍物时将队列清空。转移的复杂度降为O(1),最后的复杂度为O(KMN)

//By YY_More
#include<cstdio>
#include<iostream>
using namespace std;
char a[210][210];
int f[210][210][210];
int N,M,x,y,K,L,R,s,t,p[300],last[300],D[300];
void goup(int x){
	for (int j=1;j<=M;j++){
		L=0;R=-1;
		for (int i=N;i>0;i--)
			if (a[i][j]=='x') {L=0;R=-1;}
			else{
				while (L<=R&&f[x-1][D[R]][j]+D[R]<=f[x-1][i][j]+i) R--;
				D[++R]=i;
				while (D[L]-i>last[x]) L++;
				f[x][i][j]=f[x-1][D[L]][j]+D[L]-i;
		}
	}
};	
void godown(int x){
	for (int j=1;j<=M;j++){
		L=0;R=-1;
		for (int i=1;i<=N;i++)
			if (a[i][j]=='x') {L=0;R=-1;}
			else{
				while (L<=R&&f[x-1][D[R]][j]-D[R]<=f[x-1][i][j]-i) R--;
				D[++R]=i;
				while (i-D[L]>last[x]) L++;
				f[x][i][j]=f[x-1][D[L]][j]+i-D[L];
		}
	}
};	
void goleft(int x){
	for (int i=1;i<=N;i++){
		L=0;R=-1;
		for (int j=M;j>0;j--)
			if (a[i][j]=='x') {L=0;R=-1;}
			else{
				while (L<=R&&f[x-1][i][D[R]]+D[R]<=f[x-1][i][j]+j) R--;
				D[++R]=j;
				while (D[L]-j>last[x]) L++;
				f[x][i][j]=f[x-1][i][D[L]]+D[L]-j;
		}
	}
};	
void goright(int x){
	for (int i=1;i<=N;i++){
		L=0;R=-1;
		for (int j=1;j<=M;j++)
			if (a[i][j]=='x') {L=0;R=-1;}
			else{
				while(L<=R&&f[x-1][i][D[R]]-D[R]<=f[x-1][i][j]-j) R--;
				D[++R]=j;
				while (j-D[L]>last[x]) L++;
				f[x][i][j]=f[x-1][i][D[L]]+j-D[L];
		}
	}
};	
int main(){
	scanf("%d%d%d%d%d",&N,&M,&x,&y,&K);
	getchar();
	for (int i=1;i<=N;i++){
		for (int j=1;j<=M;j++)
		    a[i][j]=getchar();
		getchar();
	}
	for (int i=1;i<=K;i++){
		scanf("%d%d%d",&s,&t,&p[i]);
		last[i]=t-s+1;
	}	
	fill(&f[0][0][0],&f[K][N][M]+1,-50000);
	f[0][x][y]=0;
	for (int h=1;h<=K;h++)
		switch(p[h]){
			case 1:goup(h);break;
			case 2:godown(h);break;
			case 3:goleft(h);break;
			case 4:goright(h);break;
	}
	int ans=0;
	for (int i=1;i<=N;i++)
		for (int j=1;j<=M;j++)
			if (f[K][i][j]>ans) ans=f[K][i][j];
	cout<<ans<<endl;
	return 0;
}
posted on 2011-06-22 15:56  YY_More 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/yymore/archive/2011/06/22/2087110.html

本项目是一个基于SSM(Spring+SpringMVC+MyBatis)框架和Vue.js前端技术的大学生第二课堂系统,旨在为大学生提供一个便捷、高效的学习和实践平台。项目包含了完整的数据库设计、后端Java代码实现以及前端Vue.js页面展示,适合计算机相关专业的毕设学生和需要进行项目实战练习的Java学习者。 在功能方面,系统主要实现了以下几个模块:用户管理、课程管理、活动管理、成绩管理和通知公告。用户管理模块支持学生和教师的注册、登录及权限管理;课程管理模块允许教师上传课程资料、设置课程时间,并由学生进行选课;活动管理模块提供了活动发布、报名和签到功能,鼓励学生参与课外实践活动;成绩管理模块则用于记录和查询学生的课程成绩和活动参与情况;通知公告模块则实时发布学校或班级的最新通知和公告。 技术实现上,后端采用SSM框架进行开发,Spring负责业务逻辑层,SpringMVC处理Web请求,MyBatis进行数据库操作,确保了系统的稳定性和扩展性。前端则使用Vue.js框架,结合Axios进行数据请求,实现了前后端分离,提升了用户体验和开发效率。 该项目不仅提供了完整的源代码和相关文档,还包括了详细的数据库设计文档和项目部署指南,为学习和实践提供了便利。对于基础较好的学习者,可以根据自己的需求在此基础上进行功能扩展和优化,进一步提升自己的技术水平和项目实战能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值