Codeforces813DTwo Melodies(dp)

三世轮回 提交于 2019-12-04 07:03:25

链接

题意:

给定一个长度为n的序列,需要取出两个不相交的子序列,每个子序列满足相邻两个数相差一或者求余7相等。求满足条件的两个不相交的子序列长度的和最大可以是多少(n<=5000,a[i]<=1e5)

分析:

考虑dp的做法,dp[i][j]表示子序列1以a[i]结尾,子序列2以a[j]结尾时能得到的最大值。从0开始枚举i(0就代表只有一个序列),则有dp[i][j]=max(dp[i][k]+1,dp[i][j])(k<j,a[k]≡a[j]mod7||abs(a[k]-a[j])=1)
注意在枚举j时需要从i+1开始枚举这样可以避免序列1和序列2选到同一个元素。这样的做法是O(n^3),显然会T,由于a[i]<=1e5,所以可以用1e5的数组存放值为a[k]时dp[i][k]的最大值,因此可以将复杂度降为O(n*1e5).

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=5005;
int a[maxn];
int dp[maxn][maxn];
int val[100005];
int mod[8];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
    int ans=0;
    for(int i = 0;i <= n;++i)
    {
        for(int j = 1;j < i;++j){
            mod[a[j]%7]=max(mod[a[j]%7],dp[i][j]);
            val[a[j]]=max(val[a[j]],dp[i][j]);
        }
        for(int j = i+1;j <= n;++j)
        {
            dp[i][j]=dp[i][0]+1;
            dp[i][j]=max(dp[i][j],mod[a[j]%7]+1);
            dp[i][j]=max(dp[i][j],val[a[j]-1]+1);
            dp[i][j]=max(dp[i][j],val[a[j]+1]+1);
            mod[a[j]%7]=max(mod[a[j]%7],dp[i][j]);
            val[a[j]]=max(val[a[j]],dp[i][j]);
            dp[j][i]=dp[i][j];//显然dp[i][j]和dp[j][i]是等价的
            ans=max(ans,dp[i][j]);
        }
        memset(val,0,sizeof(val));
        memset(mod,0,sizeof(mod));
    }
    printf("%d\n",ans);
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!