[Algo Beat Contest 002.5 D] 我要当 gamer (gamer) 题解
tanghaocheng · · 题解
简要题面
给定
- 对于
i(1 \le i \le M) ,1 \le P_i \le N 。 -
求以下式子的最大值。
测试点 1 \sim 5
直接
时间复杂度
代码如下:
#include<bits/stdc++.h>
#define int long long
#define ll unsigned long long
#define off ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define fi first
#define se second
#define pi pair<int,int>
#define pii pair<int,pair<int,int> >
using namespace std;
const int N=305;
int n,m,T,X,t,a[N][N],cnt[N][N],ans;
void dfs(int step,int lt,int e,int sum)
{
if(step>m)
{
if(e>=0)
{
ans=max(ans,sum);
}
return;
}
for(int i=1;i<=n;i++)
{
dfs(step+1,i,e-abs(lt-i),sum+cnt[step][i]);
}
}
signed main()
{
off;
cin>>t;
while(t--)
{
cin>>n>>m>>X>>T;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
}
}
memset(cnt,0,sizeof(cnt));
ans=0;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
for(int k=max((int)(1),j-X);k<=min(n,j+X);k++)
{
cnt[i][j]+=a[i][k];
}
}
}
for(int i=1;i<=n;i++)
{
dfs(2,i,T,cnt[1][i]);
}
cout<<ans<<'\n';
}
return 0;
}
测试点 6 \sim 10
考虑 dp,
转移则是再枚举
则转移方程可表示为:
不难发现,
时间复杂度
代码如下:
#include<bits/stdc++.h>
#define int long long
#define ll unsigned long long
#define off ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define fi first
#define se second
#define pi pair<int,int>
#define pii pair<int,pair<int,int> >
using namespace std;
const int N=305;
int n,m,T,X,a[N][N],f[N][N][N],cnt[N][N],ans;
signed main()
{
off;
int c;
cin>>c;
while(c--)
{
cin>>n>>m>>X>>T;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
}
}
memset(f,0,sizeof(f));
memset(cnt,0,sizeof(cnt));
ans=0;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
for(int k=max((int)(1),j-X);k<=min(n,j+X);k++)
{
cnt[i][j]+=a[i][k];
}
}
}
for(int i=1;i<=n;i++)
{
f[1][i][0]=cnt[1][i];
}
for(int i=2;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
for(int e=0;e<=T;e++)
{
for(int k=1;k<=n;k++)
{
// f[i-1][k][e]->f[i][j][e+abs(k-j)]
if(e+abs(k-j)>T)
{
continue;
}
f[i][j][e+abs(k-j)]=max(f[i][j][e+abs(k-j)],f[i-1][k][e]+cnt[i][j]);
}
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=T;j++)
{
ans=max(ans,f[m][i][j]);
}
}
cout<<ans<<'\n';
}
return 0;
}
测试点 11 \sim 15
特殊性质 A,以及
对于每一个时刻,都可以选择花费一定的代价去获得
设第
可以定义 dp 状态,
转移时再枚举上
时间复杂度
代码如下:
#include<bits/stdc++.h>
#define int long long
#define ll unsigned long long
#define off ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define fi first
#define se second
#define pi pair<int,int>
using namespace std;
const int N=305;
int c,n,m,X,T,q[N],f[N][N],ans;
signed main()
{
off;
cin>>c;
while(c--)
{
cin>>n>>m>>X>>T;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
int x;
cin>>x;
if(x)
{
q[i]=j;
}
}
}
memset(f,0,sizeof(f));
for(int i=1;i<=m;i++)
{
f[i][0]=1;
for(int j=1;j<i;j++)
{
for(int k=abs(q[i]-q[j]);k<=T;k++)
{
f[i][k]=max(f[i][k],f[j][k-abs(q[i]-q[j])]+1);
}
}
}
ans=0;
for(int j=1;j<=m;j++)
{
for(int i=0;i<=T;i++)
{
ans=max(ans,f[j][i]);
}
}
cout<<ans<<'\n';
}
return 0;
}
正解
延续测试点
先将转移拆解,对于每个点,它可以从上一次在它左侧和它右侧转移过来。
考虑从左侧转移的情况。
若在本行我们选择了第
我们是不是可以换一下思路,如果上次我们选了第
那这样就好办了,我们定义
则转移为: