这是BC上的题目,给你n个数a1, a2, ...., an. 这n个数的和为m(m<=2^22),要在里面取出尽可能多的数字(假设t个),组成新的序列b1, b2 ... bt.使得这个序列非递减,而且(b(i) - b(i-1))也是非递减的。求这个t的最大值。
题目没有告诉n的大小。我们先排序统计出大小不同的数字nn[], 和每个数字出现的次数mm[],可以算出不同的数字不会超过3000
dp[i][j] (j>=i) 表示以nn[i] 和nn[j]为所求序列的最末尾两个数字,这种情况下的序列的长度.
dp[i][i] = mm[i], dp[i][j] = max(dp[i][j], dp[k][i] + 1), (k<=i)
直接算的话复杂度O(n^3),不可取。我们可以发现上面的转移中随着j的增大k是随着减小的,可以优化到O(n^2).
<span style="font-size:14px;">#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<string.h>
using namespace std;
#define N 10000000
#define M 3000
int a[N],dp[M][M],s[M],num[M];
int n,m;
int main()
{
int t;
cin>>t;
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
int tot=0;
int x=1;
a[n]=-1;
for(int i=0;i<n;i++)
if(a[i]!=a[i+1]){
num[tot]=a[i];
s[tot++]=x;
x=1;
}
else x++;
int ans=0;
for(int i=0;i<tot;i++)
{
dp[i][i]=s[i];
int k=i;
int ma=0;
ans=max(dp[i][i],ans);
for(int j=i+1;j<tot;j++)
{
while((num[j]-num[i])>=(num[i]-num[k])&&k>=0)
{
ma=max(ma,dp[k][i]);
k--;
}
dp[i][j]=ma+1;
ans=max(ans,dp[i][j]);
}
}
printf("%d\n",ans);
}
return 0;
}
</span>