【解题报告】Power收集

东方Project相关试题 Power收集

(注:我不是东方众哦 但下次回家可以试着玩一下

传送门

先读题啦

n*m矩阵,其中有K个格子上有P点,价值val[i][j],从第一行任意格子出发,每秒向下走一行,左右最多各走T格,问能收集的最大val

先想想暴力のDP

这不就是IOI1994那道大水题咩!???

暴力转移一下

可以设dp[i][j]为到达(i,j)时的max值,O(n^3)

dp[i][j]=max(dp[i-1][k]+val[i][j])(k属于什么大家都知道吧。。。不想打数学符号了)

只有40pts。。。那我也把代码放出来好啦,养成写暴力的好习惯

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define int long long

using namespace std;

const int maxn=4010;

inline int read()
{
	int w=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch=='-')
		{
			f=-1;
		}
		ch=getchar();
	}
	while(ch>='0' && ch<='9')
	{
		w=(w<<3)+(w<<1)+(ch^48);
		ch=getchar();
	}
	return w*f;
}

int n,m,k,t;

int val[maxn][maxn];

int dp[maxn][maxn];

signed main()
{
	n=read();
	m=read();
	k=read();
	t=read();
	
	for(int i=1;i<=k;i++)
	{
		int x=read();
		int y=read();
		val[x][y]=read();
	}
	
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			for(int k=max(1ll,j-t);k<=min(m,j+t);k++)
			{
				dp[i][j]=max(dp[i][j],dp[i-1][k]+val[i][j]);
			}
		}
	}
	
	int ans=0;
	
	for(int i=1;i<=m;i++)
	{
		ans=max(ans,dp[n][i]);
	}
	
	cout<<ans;
	
	return 0;
}

单调队列优化

对于每一行的某个值,都是在上一行可行的范围里选一个最大的加上这个val,如何在上一行搞一个max值呢?我们发现,每一行找max值时都是在一个固定的区间长度内的,就像是一个区间从左到右滑。。。

从左向右滑???滑动。。。窗口???

那不就是单调队列么(O(n*m))

用它维护每一(i-1)行的max值就好啦,代码很短的

AC 代码

#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<deque>
#include<algorithm>

using namespace std;

const int maxn=4010;

inline int read()
{
	int w=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch=='-')
		{
			f=-1;
		}
		ch=getchar();
	}
	while(ch>='0' && ch<='9')
	{
		w=(w<<3)+(w<<1)+(ch^48);
		ch=getchar();
	}
	return w*f;
}

int n,m,k,t;

int dp[maxn][maxn];

int val[maxn][maxn];

int main()
{
	n=read();
	m=read();
	k=read();
	t=read();
	
	for(int i=1;i<=k;i++)
	{
		int x=read();
		int y=read();
		val[x][y]=read();
	}
	
	for(int i=1;i<=n;i++)
	{
		deque <int> q;
		
		int r=0;
		
		for(int j=1;j<=m;j++)
		{
			while(r<m && r<j+t)
			{
				r++;
				while(!q.empty() && dp[i-1][q.back()]<=dp[i-1][r])
				{
					q.pop_back();
				}
				q.push_back(r);
			}
			
			while(!q.empty() && (j-t)>q.front())
			{
				q.pop_front();
			}
			
			dp[i][j]=dp[i-1][q.front()]+val[i][j];
		}
	}
	
	int ans=0;
	
	for(int i=1;i<=m;i++)
	{
		ans=max(ans,dp[n][i]);
	}
	
	cout<<ans;
	
	return 0;
}

どんなに美しく犠牲になるかを考えるよりも、どうやって最後まで美しく生きるかを考えてみましょう。

posted @ 2022-09-20 08:57  NinT_W  阅读(13)  评论(0编辑  收藏  举报