[USACO17JAN] Subsequence Reversal P

根据数据范围,不难想到 DP 状态应该是 \(n^4\) 级别的。

先考虑当没有反转区间的操作时如何转移。

\(dp_{l,r,L,R}\) 表示当前区间为 \(l\sim r\),值域 \(\in [L,R]\) 时的答案。转移时枚举四个维度,可以从 \(dp_{l,r,L,R-1},dp_{l,r,L+1,R},dp_{l+1,r,L,R},dp_{l,r-1,L,R}\) 转移过来。

加上翻转操作后,我们思考其本质。翻转一个子序列可以理解为交换某几对数字的位置,这样的话相当于如果 \(a_l=R\) 或者 \(a_r=L\) 的话,我们可以通过翻转 \(l\sim r\) 中的任意一个包含 \(l,r\) 的子序列来满足条件,即 \(dp_{l,r,L,R}=dp_{l+1,r-1,L,R}+[a_l=R]+[a_r=L]\)

由于区间 DP 按照区间从小到大的顺序,故可以保证这样的翻转满足题目条件,所以这道题就结束了。

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
	int w=1,s=0;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
	return w*s;
}
const int mod=998244353;
const int maxn=51;
const int inf=3e17+7;
int n,a[maxn],dp[maxn][maxn][maxn][maxn];
signed main()
{
#ifdef Lydic
	freopen(".in", "r", stdin);
	freopen(".out", "w", stdout);

//  #else
//   	freopen("Stone.in","r",stdin);
//   	freopen("Stone.out","w",stdout);
#endif
    cin>>n;
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=n;i++)
        for(int l=1;l<=a[i];l++)
            for(int r=a[i];r<=50;r++)
                dp[i][i][l][r]=1;
    for(int len=2;len<=n;len++)
    {
        for(int l=1;l<=n-len+1;l++)
        {
            int r=l+len-1;
            for(int lenn=1;lenn<=50;lenn++)
            {
                for(int L=1;L<=50-lenn+1;L++)
                {
                    int R=L+lenn-1;
                    dp[l][r][L][R]=max(dp[l][r][L+1][R],dp[l][r][L][R-1]);
                    dp[l][r][L][R]=max(dp[l][r][L][R],dp[l+1][r][L][R]+(a[l]==L));
                    dp[l][r][L][R]=max(dp[l][r][L][R],dp[l][r-1][L][R]+(a[r]==R));
                    dp[l][r][L][R]=max(dp[l][r][L][R],dp[l+1][r-1][L][R]+(a[l]==R)+(a[r]==L));
                }
            }
        }
    }
    cout<<dp[1][n][1][50];
	return 0;
}

posted @ 2024-10-28 12:36  Redamancy_Lydic  阅读(4)  评论(0编辑  收藏  举报