atcoder E - Greedy Ant(最优解等价+dp)

E - Greedy Ant

Grice题解最开始看不懂神的思路,还评论请教了一波应该是个集训队大佬QaQ


snuke在当前轮直接选取,那么状态会非常不好记录 我们保留snuke在之前轮,选择放弃暂时不选的次数,然后等蚂蚁走到这来了再选
虽然这个跟原游戏不同,但显然其不会优于最优解,也包含最优解

状态表示: f l , r , k f_{l,r,k} fl,r,k​开区间 ( l , r ) (l,r) (l,r)内的糖果已经被取走了, snuke \text{snuke} snuke还能选择 k k k次的最优解
状态转移:

  • 满足 k > 0 k>0 k>0,那么 snuke \text{snuke} snuke可以选择 l l l或者 r r r,则分别转移到 f l − 1 , r , k − 1 + a l f_{l-1,r,k-1}+a_l fl−1,r,k−1​+al​和 f l , r + 1 , k − 1 + a r f_{l,r+1,k-1}+a_r fl,r+1,k−1​+ar​
  • 目前 snuke \text{snuke} snuke不选择,则对手选择那么用 f l − 1 , r , k + 1 f_{l-1,r,k+1} fl−1,r,k+1​或者 f l , r + 1 , k + 1 f_{l,r+1,k+1} fl,r+1,k+1​转移(按照题意,这里转移固定,取 a l , a r a_l,a_r al​,ar​较大的一个)
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=410;
int n;
ll f[N][N][N],a[N];
ll dp(int l,int r,int k)
{
    if(f[l][r][k]!=-1) return f[l][r][k];
    
    ll &ans=f[l][r][k];
    ans=0;
    if(l>=1)
    {
        if(k) ans=max(ans,a[l]+dp(l-1,r,k-1));
        if(a[l]>a[r]) ans=max(ans,dp(l-1,r,k+1));
    }
    if(r<=n)
    {
        if(k) ans=max(ans,a[r]+dp(l,r+1,k-1));
        if(a[r]>a[l]) ans=max(ans,dp(l,r+1,k+1));
    }
    return ans;
    
}
int main()
{
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    memset(f,-1,sizeof f);
    for(int i=0;i<=n;i++)
        cout<<dp(i,i+1,1)<<'\n';
    return 0;
}

上述博客博主太热心了,并且讲的非常详细,以至于题解总结基本都是抄的~~

上一篇:2021牛客训练营 F.魏迟燕的自走棋(贪心并查集)


下一篇:FL Studio水果软件20.8插件使用技巧分享