【解题报告】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;
}
どんなに美しく犠牲になるかを考えるよりも、どうやって最後まで美しく生きるかを考えてみましょう。