题目大意:
while(L<=R)
{
int mid=(L+R)/2;
if(dp[mid]>=value&&dp[mid-1]<=value)
return mid;
else if(dp[mid]
L=mid+1;
else
R=mid-1;
}
return L;
int n,m;
int i,j;
int x;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(i=1;i<=n;i++)//按顺序记录a串中各字符的位置
{
scanf("%d",&x);
a[x]=i;
}
j=0;
for(i=1;i<=m;i++)
{
scanf("%d",&x);
if(a[x]) //只保存a,b串公有字符
b[++j]=a[x];//将问题转化成了最长递增子序列a[x]是x在a串的位置
}
int len=j;//记录b串的长度len
int R=0;//用来保存最长递增子序列的长度
j=0;
dp[0]=-1;//初始值吗!
for(i=1;i<=len;i++)//动态规划最长递增子序列,这个不理解的话可以网上自己找!!
{
if(b[i]>dp[R])
j=++R;
else
j=Find(1,R,b[i]);
dp[j]=b[i];
}
printf("%d\n",R);//输出最长递增子序列的长度不就行了
}
给你两串整数,要求你输出最长公共子序列(串的长度是100000.)时间限制:1000 ms | 内存限制:65535 KB
所以无论是时间上还是空间上这都是需要进行比较精心的优化过后才行。这题我做了老半天然后各种优化最终都没成功,都是超时了,然后dp数组还开不到100000*100000;而且这题网上的代码页找不到,最后只能求助大师了,看完大师的代码后才恍然大悟,只恨自己太笨。仰天长啸,然后将解题思路奉献给更多的人吧。
#include
#include
#define N 100010
int a[N],b[N],dp[N];
int Find(int L,int R,int value)//最长递增子序列二分查找。
{
}
int main()
{
}
好了,我相信只要你认真读完代码,应该也就对本题了然于心了。
优化的关键在于题目给出每个字符都不相同,且每个字符都小于100000.所以可以开数组来保存所有出现在第一个串中的字符出现的位置,然后第二个串只保存在第一个串中出现过的字符的位置。这样在第二个串中递增出现的数字就和第一个串中出现的顺序就肯定是公共子串。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>
using namespace std;
#define MAXN 275005
#define MOD 1000000
#define LL long long int
int z[100005];
int b[100005];
int fz[100005];
int fznum;
int find(int l, int r, int x)
{
while (l < r)
{
int m = (l + r) >> 1;
if (fz[m] < x)
l = m + 1;
else
r = m;
}
return l;
}
int main()
{
int T, n, m, x;
while (~scanf("%d %d", &n, &m))
{
memset(z, -1, sizeof(z));
for (int i = 0; i < n; ++i)
{
scanf("%d", &x);
z[x] = i;
}
int bnum = 0;
for (int i = 0; i < m; ++i)
{
scanf("%d", &x);
if (z[x] >= 0)
{
b[bnum++] = z[x];
}
}
fznum = 0;
for (int i = 0; i < bnum; ++i)
{
if (!fznum)
{
fz[fznum++] = b[i];
}
else
{
if (b[i] > fz[fznum - 1])
fz[fznum++] = b[i];
else
{
fz[find(0, fznum - 1, b[i])] = b[i];
}
}
}
printf("%d\n", fznum);
}
}