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