Hdu 5064 Find Sequence(dp)

来源:互联网 发布:淘宝佣金网 编辑:程序博客网 时间:2024/06/18 13:53

题目链接

Find Sequence

Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 192    Accepted Submission(s): 58


Problem Description
Give you an positive integer sequence a1,a2,,ai,,an, and they satisfy a1+a2++ai++an=M(0<M222).
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) b1b2bt
(2) b2b1b3b2btbt1
We can find many sequences b1,b2,b3,,bt. But we only want to know maximum t.
 

Input
The first line in the input file is an Integer T(1T30).
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.
 

Output
For each test case, output the maximum t.
 

Sample Input
26 193 2 1 3 4 61 41943044194304
 

Sample Output
51
Hint
For 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 1000000007typedef 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;}



0 0
原创粉丝点击