Find Sequence
Time Limit: 5000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 192 Accepted Submission(s): 58
We can find new sequence b1=aid1,b2=aid2,…,bx=aidx,…,by=aidy,…,bt=aidt , where if x != y then idx!=idy . and this sequence satisfy:
(1) b1b2…bt
(2) b2−b1b3−b2⋯bt−bt−1
We can find many sequences b1,b2,b3,…,bt . But we only want to know maximum t.
The first line of each test case contains two integer n,M(0<M222) .
Then a line have n integer, they represent a1,a2,…,ai,…,an .
2 6 19 3 2 1 3 4 6 1 4194304 4194304
5 1HintFor the first testcase, The Sequence is 1 2 3 4 6
题意:输入n,m。输入n个数a1,a2,,,an。a1+a2...+an==m。从a数列中选一些数,构成b数列,每个数只能用一次,使得b数列满足,b1<=b2....<=bt,b2-b1<=b3-b2<=b4-b3.....<=bt-bt-1。输出最大的t。已知m<=2^22。
题解:已知m,我们可以算出a数列中不同的数的个数cnt大概为sqrt(m ),大概是3000。
将a数列去重并按从小到大排序。
我们用dp[ i ][ j ] 表示,以第 i 个数结尾,它的前一个数为第 j 个数,b数列的最大长度。
那么,dp[ i ][ i ]=a[ i ]在原数列中的个数。
很容易写成cnt^3的转移方程:
dp[ i ][ j ]=max(dp[ i ][ j ] , dp[ j ][ k ]+1) , k<=j ,a[ i ]-a[ j ]>=a[ j ]-a[ k ] 。
我们注意到:
dp[ i+1 ][ j ]=max( dp[ i+1 ][ j ], dp[ j ][ k ]+1) , k<=j , a[ i+1 ]-a[ j ]>=a[ j ]-a[ k ]。
由于a[ i+1 ]-a[ j ]>a[ i ]-a[ j ]。
所以 k 满足dp[ i ][ j ]一定满足dp[ i+1 ][ j ]。所以重复的区间就不用枚举了。
我们用p[ j ] 记录可以更新dp[ i ][ j ] 最小的k,那么转移就可以写成:
dp[ i+1 ][ j ]=max(dp[ i ][ j ],max(dp[ j ][ k ]+1) ),k<p[ j ],a[ i+1 ]-a[ j ]>=a[ j ]-a[ k ] 。
这样复杂度就优化到了O(cnt^2)。
代码如下:
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<vector>
#include<iostream>
#include<string.h>
#include<string>
#include<math.h>
#include<stdlib.h>
#define inff 0x3fffffff
#define eps 1e-8
#define nn 11000000
#define mod 1000000007
typedef long long LL;
const LL inf64=LL(inff)*inff;
using namespace std;
int n,m;
int a[nn];
int b[3100];
int dp[3100][3100];
int p[3100];
int main()
{
int t,i,j,k;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+n+1);
a[0]=-1;
memset(dp,0,sizeof(dp));
int ix=1;
int cnt=0;
for(i=1;i<=n;i++)
{
if(a[i]!=a[i-1])
{
b[++cnt]=a[i];
dp[cnt][cnt]=1;
ix=1;
}
else
{
ix++;
dp[cnt][cnt]=ix;
}
}
int ans=0;
for(i=1;i<=cnt;i++)
p[i]=i;
for(i=1;i<=cnt;i++)
{
for(j=1;j<i;j++)
{
dp[i][j]=max(dp[i][j],dp[i-1][j]);
for(;p[j]>=1;p[j]--)
{
k=p[j];
if(b[i]-b[j]>=b[j]-b[k])
{
dp[i][j]=max(dp[i][j],dp[j][k]+1);
}
else
break;
}
ans=max(ans,dp[i][j]);
}
ans=max(ans,dp[i][i]);
}
printf("%d\n",ans);
}
return 0;
}