最长上升子列 LIS 学习小记 Poj 2533 +CF 261D

做dp时遇到的知识点,学习了三种方法:dp,二分,树状数组优化。

树状数组优化的在网上貌似很难搜到……这部分参考了学长的博客:http://www.cnblogs.com/jianglangcaijin/archive/2013/01/18/2865811.html

三种方法用下来还是个人觉得二分最好用……但树状数组貌似最有前途……


Poj 2533

#include 

int data[1005];
int dp[1005];  //dp[i]表示以第i个位置为终点的最长上升子序列的长度

/*
对于任意的 0=data[i],则data[i]=1
*/

int main ()
{
	int n,i;
	scanf("%d",&n);
	for (i=0;i

/*参考链接http://www.slyar.com/blog/longest-ordered-subsequence.html
开一个栈,每次取栈顶元素top和读到的元素temp做比较,如果temp > top 则将temp入栈;如果temp < top则二分查找栈中的比temp大的第1个数,并用temp替换它。 最长序列长度即为栈的大小top。

这也是很好理解的,对于x和y,如果x < y且Stack[y] < Stack[x],用Stack[x]替换Stack[y],此时的最长序列长度没有改变但序列Q的''潜力''增大了。

举例:原序列为1,5,8,3,6,7

栈为1,5,8,此时读到3,用3替换5,得到1,3,8; 再读6,用6替换8,得到1,3,6;再读7,得到最终栈为1,3,6,7。最长递增子序列为长度4。
*/


#include 

int stack[1005];
 
int main ()
{
	int n;
	scanf("%d",&n);
	int top=0,temp;
	stack[0]=-1;    //输入数据大于等于0
	for (int i=0;istack[top]) //比栈顶元素大数就入栈
			stack[++top]=temp;
		else        //否则二分检索栈中比temp大的第一个数
		{
			int low=1,high=top,mid;
			while (low<=high)
			{
				mid=(low+high)>>1;
				if (temp > stack[mid])
					low=mid+1;
				else
					high=mid-1;
			}
			stack[low]=temp;  //用temp替换
		}
	}
	printf("%d\n",top);  //最长序列数就是栈的大小
	return 0;
}

CodeForces 261D

题目链接:http://codeforces.com/problemset/problem/261/D

题意:给出数列b,其中最大的元素不超过maxb,利用将b重复t次的方式构造数列a,求a中LIS的长度。

思路:当t>=maxb时,b中不同元素的个数即为所求。否则利用树状数组优化

#include 
#include 
#include 
#include 
#define max(x,y) ((x)>(y)?(x):(y))
using namespace std;


int K,n,maxb,t;
int b[100005];
int ans[100005];   //ans[i]表示以这个数为终点的最长上升子序列的长度
int c[100005];     //树状数组

void update (int x,int d)
{
    while (x<=maxb)
    {
        if (d>c[x])
			c[x]=d;
        x+=x&-x;
    }
}

int get (int x)    //查找小于等于x的数所构成的LIS的长度
{
    int ans=0;
    while (x>0)
    {
        ans=max(ans,c[x]);
        x-=x&-x;
    }
    return ans;
}

int cal ()
{
	memset (c,0,sizeof(c));
	memset (ans,0,sizeof(ans));
	int i,j,k;
	for (i=1;i<=t;i++)
		for (j=1;j<=n;j++)
		{
			k=get(b[j]-1)+1;
			if (k>ans[j])   //更新
			{
				ans[j]=k;
				update(b[j],k);
			}
		}
	return *max_element(ans+1,ans+n+1);
}

int main ()
{
	scanf("%d%d%d%d",&K,&n,&maxb,&t);
    int i;
    while (K--)
    {
        for (i=1;i<=n;i++)
			scanf("%d",&b[i]);
        if (t>=maxb)    //输出不同的数的个数
        {
            sort(b+1,b+n+1);
            printf("%d\n",unique(b+1,b+n+1)-(b+1));
            continue;
        }
        printf("%d\n",cal());
    }
    return 0;
}


你可能感兴趣的:(动态规划-字符串相关,学习轨迹)