链接
题意:
给定一个长度为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;
}