感觉这个专题真不好捉,伤心了,慢慢啃吧,孩纸

地址http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28195#overview

密码  acmore

Problem A HDU 1159 Common Subsequence

这算是LCS里面最简单了的吧

解题方法见http://www.cnblogs.com/gj-Acit/p/3236384.html

下面随便贴上两段代码

 #include <stdio.h>
#include <string.h>
#define MAX(a,b) (a>b?a:b) char X[],Z[];
int Com[][]; int main()
{
memset(X,,sizeof(X));
memset(Z,,sizeof(Z));
while(~scanf("%s%s", X, Z))
{
memset(Com,,sizeof(Com));
int LenX = strlen(X), LenZ = strlen(Z);
for(int i=;i<LenX;i++)
{
for(int j=;j<LenZ;j++)
{
if(X[i] == Z[j])Com[i+][j+] = Com[i][j]+;
else Com[i+][j+] = MAX(Com[i][j+], Com[i+][j]);
}
}
printf("%d\n",Com[LenX][LenZ]);
}
return ;
}

下面这个空间复杂度要小一些

 #include <stdio.h>
#include <string.h>
#define MAX(a,b) (a>b?a:b) char X[],Z[];
int Com[][]; int main()
{
memset(X,,sizeof(X));
memset(Z,,sizeof(Z));
while(~scanf("%s%s", X, Z))
{
memset(Com,,sizeof(Com));
int LenX = strlen(X), LenZ = strlen(Z);
int key = ;
for(int i=;i<LenX;i++)
{
key = !key;
for(int j=;j<LenZ;j++)
{
if(X[i] == Z[j])Com[key][j+] = Com[!key][j]+;
else Com[key][j+] = MAX(Com[!key][j+], Com[key][j]);
}
}
printf("%d\n",Com[key][LenZ]);
memset(X,,sizeof(X));
memset(Z,,sizeof(Z));
}
return ;
}

Problem B HDU 1513Palindrome

这道题最开始就看到好多人MLE,就想肯定是开了5000*5000,那时候自己也还不知道可以压缩空间,况且5000*5000时限上应该也会超时才对,加上自己本来就没有看LCS和LIS的资料,就不打算做了,到后来,在网上看了O(nlogn)的解法,就想试着写写看,虽知道不尽不好写,还RE了好多次,比赛结束后才慢慢明白原来自己在吧问题转化时把数组开小了很多,至于如何转化,题解放在http://www.cnblogs.com/gj-Acit/p/3236384.html

后来改了半天,也想尽力把空间开小一点,最后只能是把转化后的数组开到了100 * 5000,虽然理论上应该要开5000 * 5000的,我想应该是本题数据比较水吧。最后总算是Ac了

2460 KB   109 ms

 #include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define MAXN 5005
int A[*MAXN];
int x[][];
int num[],d[MAXN]; int Binary_search(int l,int r,int num)
{
int mid ;
while(r-l>)
{
mid = l+(r-l)/;
if(d[mid]<num)l = mid;
else r = mid;
}
return l;
} int LIS(int N)
{
memset(d,,sizeof(d));
int len = ;
d[len] = ;
for(int i=;i<N;i++)
{
if(A[i]>d[len])
{
d[++len] = A[i];
}
else
{
int j = Binary_search(, len, A[i]);
d[j+] = A[i];
}
}
return len;
} int cmp(int a,int b)
{
return b<a;
} int Record(char *str)
{
memset(num,,sizeof(num));
int len = strlen(str)-;
int key = len;
while(len>=)
{
x[(int)str[len] - ''][num[(int)str[len] - '']++] = key-len;
len--;
}
for(int i=;i<;i++)if(num[i])
{
sort(x[i], x[i] + num[i], cmp);
}
len = strlen(str);
int countt = ;
for(int i=;i<len;i++)
{
for(int j=;j<num[(int)str[i] - ''];j++)
{
A[countt++] = x[(int)str[i] - ''][j];
}
}
return countt;
} int main()
{
int N; char str[MAXN];
while(~scanf("%d%*c", &N))
{
scanf("%s",str);
memset(A,,sizeof(A));
int len = Record(str);
int ans = LIS(len);
printf("%d\n", N-ans);
}
return ;
}

然后后来居然后人用n^2 才300+Ms就过了,我不得不说数据的确很水了

276 KB    375 ms

 #include <stdio.h>
#include <string.h>
#define MAX(a,b) a>b?a:b int N,f[][];
char str1[],str2[]; int LCS()
{
memset(f,,sizeof(f));
int key = ;
for(int i=;i<N;i++)
{
key = !key;
for(int j=;j<N;j++)
{
if(str1[i] == str2[j])
{
f[key][j+] = f[!key][j]+;
}
else f[key][j+] = MAX(f[!key][j+], f[key][j]);
}
}
return MAX(f[][N], f[][N]);
} int main()
{
while(~scanf("%d", &N))
{
scanf("%s", str1);
for(int i=;i<N;i++)
{
str2[i] = str1[N--i];
}
printf("%d\n", N-LCS());
}
return ;
}

Problem C HDU 4545魔法串

这道题我用的方法是,直接将各种变换存放在一个数组里面,并记录每个字母可以变化为其他字母的个数,这样在对a额b比较的时候,如若在a[i]之前的字母在b[j]之前都已经找到了匹配的字母,那么在比较a[i]和b[j]时,就直接现将a[i]和b[j]比较,如果相同的话那么i和j都直接挑到下一个,否者比较a[i]和可以替换b[j]的字母,如果有相同的,说明可以通过替换来让他们匹配起来,再否则,j直接跳到下一个,再和a[i]比较,直到有一个字符串找完。如果a找完了,说明匹配完了。

 #include <stdio.h>
#include <string.h>
#define GetNum(b) ((int)b-'a')
#define MAX(a,b) ( (a) > (b) ? (a) : (b) ) char Xi[], Ming[], Exchange[][];//由于只有阿26个字母,所以前面设置大小为26
int num[], M, Case; int main()
{
int T=;
while(~scanf("%d%*c", &Case))while(Case--)
{
memset(num, , sizeof(num));
memset(Exchange, , sizeof(Exchange));
scanf("%s %s",Xi,Ming);
scanf("%d%*c", &M);
char a,b;
for(int i = ; i < M; i ++ )//直接将各种变换放在Exchange数组里面
{
scanf("%c %c%*c",&a, &b);
Exchange[ GetNum(a) ][ num[GetNum(a)] ++ ] = b;//num数组记录每个字母可以被替换的种数
}
int indexXi = , indexMing = , LenXi = strlen(Xi), LenMing = strlen(Ming);
while(indexXi < LenXi && indexMing < LenMing)
{
if(Xi[indexXi] == Ming[indexMing])//先和自身比较
{
indexXi++;
indexMing++;
continue;
}
int flag = ;
for(int i=;i<num[GetNum(Ming[indexMing])]; i++)//再和Ming可以被替换的字母比较
{
if(Xi[indexXi] == Exchange[GetNum(Ming[indexMing])][i])
{
flag = ;
indexMing ++;
indexXi ++;
break;
}
}
if(flag)indexMing ++;//若都找不到,那么Ming直接跳到下一个
}
printf("Case #%d: %s\n", ++T, (LenXi == indexXi) ? "happy" : "unhappy");
}
return ;
}

Problem D HDU 1257   最少拦截系统

题解见http://www.cnblogs.com/gj-Acit/p/3238689.html

Problem E HDU 1677

Nested Dolls

题目的意思是说一些娃娃有大小不同的很多个,小的可以放进大的里面,前提条件是它的宽W和高H,都比大的要小。

其实最开始看到这个题我也不会,只是在之前受人的指点说这个题和第D题一样。而他的思路就是,先将这些娃娃先按照W(H也可以的)逆序排序,这样一来的话前面对娃娃都是W比后面大的,所以我们就只需要讨论H的比较。所以这时就只需要前面的娃娃的H比后面的要大的话,那后面的娃娃也就可以放进前面的娃娃里面,也就转化为了有一个序列,求最少严格递减子序列有多少个,也就转化为了上题。

有一点需要注意的就是,如果两个娃娃他们的W一样大的话,要按照他们的H从小到大排列。举个例子来说明:序列

W 6  6  6  6  6  5  5  5  5

H  6  5  4  3  2  1  2  4  5

目前是将W由逆序排序,H不排,(其实H按逆序排序分析结果是一样的),那么由于我们此时只考虑H而不考虑W,所以按照求最长升序子序列的方法(这里需要先知道一下求最长升序子序列nlogn的解法),W为6的H为6的那个娃娃会把W为5H为1的包含进去,W为6H为5的娃娃会把W为5H为2的包含进去,而之后W为6的却都不可以把之后w为5的放在它内部了,所以此时结果就是7,而实际上6->5,5->4,4->2,3->1我们就只需要5个娃娃就行了。

而最后将H升序排序的目的就是只将W比当前小的而且保证每个都尽量去包含与他H接近的哪一个娃娃,这样贪心结果就不会有错。

W  6  6  6  6  6  5  5  5  5

H   2  3  4  5  6  1  2  4  5

这里每个W为6的都可以包含以后W为5的娃娃了。所以是最优解。

贴代码

 #include <stdio.h>
#include <string.h>
#include <algorithm>
#define MAX(a, b) ( (a) > (b) ? (a) : (b))
#define mem0(a) memset(a, 0, sizeof(a))
using namespace std; struct node {int w,h;}Doll[];
int f[];
int N,T; int cmp(node a,node b)
{
if(a.w != b.w)return a.w > b.w;
return a.h < b.h;
} int main()
{
while(~scanf("%d", &T))while(T--)
{
scanf("%d", &N);
mem0(Doll); mem0(f);
for(int i=;i<=N;i++)
{
scanf("%d%d", &Doll[i].w,&Doll[i].h);
}
sort(Doll+, Doll++N,cmp);
int ans = ;
for(int i=;i<=N;i++)
{
int l = , r = ans, mid;
while(l<r)
{
mid = (l+r)/;
if(f[mid] <= Doll[i].h) l = mid + ;
else r = mid;
}
f[l] = Doll[i].h;
if(l == ans) ans ++;
}
printf("%d\n", ans);
}
return ;
}

Problem F HDU 1423

Greatest Common Increasing Subsequence

裸的LCIS,百度之或见http://www.cnblogs.com/gj-Acit/p/3236384.html

 #include <stdio.h>
#include <string.h>
#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
int T, n1, n2, a, f[], b[];
int main()
{
while(~scanf("%d", &T))while(T--)
{
memset(f,,sizeof(f));
scanf("%d", &n2);
for(int i=;i<=n2;i++) scanf("%d", &b[i]);
scanf("%d", &n1);
for(int i=;i<=n1;i++)
{
scanf("%d", &a);
int maxx = ;
for(int j=;j<=n2;j++)
{
if(a > b[j] && maxx < f[j]) maxx = f[j];
if(a == b[j]) f[j] = maxx + ;
}
}
int ans = ;
for(int i=;i<=n2;i++) ans = MAX(ans, f[i]);
printf("%d\n", ans);
if(T)printf("\n");
}
return ;
}

Problem G HDU 4512

吉哥系列故事――完美队形I

题目大意就不介绍了。感觉这道题挺不错的。

这道题还是求最长公共上升子序列有多长,只是比上题复杂了一点点。

由于是要求两端相等但也要使得序列升序且最长,那我们就枚举中点mid(1~N),这样的话那我们就只需要比较a[1~mid]和a[N~mid]这两个区间的最升序长公共子序列的长度,再找到他们最长的长度。见代码:

 /*
只有注释位置与普通的LCIS略有改动,其他都一样
*/
int Max = ;
for(int mid = ; mid <= N;mid ++)//枚举中点
{
mem0(f);
int key=,ans = ;
for(int i=;i<=mid;i++)//左边区间从1~mid
{
int Maxx = ;
for(int j=N;j>=mid;j--)//右边区间从N~mid
{
if(a[i] > a[j] && Maxx < f[j])Maxx = f[j];
if(a[i] == a[j])
{
f[j] = Maxx+;
if(ans < f[j]*)//如果更优,更新
{
ans = f[j]*;
if(j == mid)ans --;//如果j==mid,也就是说此时,而此时更优,也就是说mid更优,
//说明mid被计算在了最长的序列当中,那它就在*2时被计算了2次,所以-1
}
}
}
}
Max = MAX(Max, ans);//找出最大的解
}
printf("%d\n", Max);

我们再看看上面的代码:

for(int mid = 1;mid <= N; mid ++ )

{

  for(int i = 1 ; i <= mid ; i ++ )  {

  }

}

可以注意到在计算mid的时候,i从1~mid循环了一次,而计算mid+1时i从1~mid又计算了一次,而实际上这两次计算的结果f[N~(mid+1)]都是一样的(因为相当于a序列是a[1~mid],b序列是a[N~mid+1],两次计算他们的最长公共升序子序列的长度肯定是一样的),那么为了免去这个重复的计算,在mid取到mid+1的时候,i便直接从mid+1开始,就可以直接使用前面已经计算出来的mid的所有的值,而省去x从1~mid的重复计算。

所以这时我们就只需要两个循环,i表示的便是枚举的中点mid。

 #include <stdio.h>
#include <string.h>
#include <algorithm>
#define MAX(a, b) ( (a) > (b) ? (a) : (b))
#define mem0(a) memset(a, 0, sizeof(a))
using namespace std; int a[], f[];
int Case, N; int main()
{
while(~scanf("%d", &Case))while(Case--)
{
mem0(a); mem0(f);
scanf("%d", &N);
for(int i=;i<=N;i++)
{
scanf("%d", &a[i]);
}
int ans = ;
for(int i=;i<=N;i++)//i表示的是mid的值
{
int Max = , key = ;
for(int j=N;j>=i;j--)//j依然从N取到mid(i)
{
if(a[i] > a[j] && Max < f[j])Max = f[j];
if(a[i] == a[j])
{
f[j] = Max+;
if(ans < f[j]*)
{
ans = f[j]*;
key = j;//记录两个序列最后一次有元素相同的时候的j的值
}
}
}
if(key == i)ans --;//如果“b”序列最后一次和“a”序列相同的时候是出现在“mid”的位置,长度-1
}
printf("%d\n", ans);
}
return ;
}

8.3 LIS LCS LCIS(完结了==!)的更多相关文章

  1. LIS+LCS+LCIS

    PS:本篇博文均采用宏#define FOR(i, a, n) for(i = a; i <= n; ++i) LIS:最长上升子序列 废话不多说:http://baike.baidu.com/ ...

  2. LIS LCS LCIS (主要过一遍,重在做题)

    只详细讲解LCS和LCIS,别的不讲-做题优先. 菜鸟能力有限写不了题解,可以留评论,我给你找博客. 先得理解最长上升子序列吧,那个HDOJ拦截导弹系列可以做一下,然后用o(n)log(n)的在做一遍 ...

  3. LIS && LCS && LCIS && LPS && MCS模板

    1. LIS (Longest Increasing Subsequence) O (n^2): /* LIS(Longest Increasing Subsequence) 最长上升子序列 O (n ...

  4. LIS&&LCS&&LCIS

    LIS #include<bits/stdc++.h> using namespace std; int n,a[100005],b[100005],ji; int main(){ cin ...

  5. 线性DP总结(LIS,LCS,LCIS,最长子段和)

    做了一段时间的线性dp的题目是时候做一个总结 线性动态规划无非就是在一个数组上搞嘛, 首先看一个最简单的问题: 一,最长字段和 下面为状态转移方程 for(int i=2;i<=n;i++) { ...

  6. LIS LCS n^2和nlogn解法 以及LCIS

    首先介绍一下LIS和LCS的DP解法O(N^2) LCS:两个有序序列a和b,求他们公共子序列的最大长度 我们定义一个数组DP[i][j],表示的是a的前i项和b的前j项的最大公共子序列的长度,那么由 ...

  7. LIS和LCS LCIS

    首先介绍一下LIS和LCS的DP解法O(N^2) LCS:两个有序序列a和b,求他们公共子序列的最大长度 我们定义一个数组DP[i][j],表示的是a的前i项和b的前j项的最大公共子序列的长度,那么由 ...

  8. LIS,LCS,LICS 学习笔记

    1.最长上升子序列(LIS) 子序列: 1.可以不连续 2.相对位置不变 dp[i][j] 表示前i位置,最大值为j的LIS长度 1. dp[i-1][j] 前i-1位置,最大值为j的LIS长度 (没 ...

  9. dp入门(LIS,LCS)

    LCS

随机推荐

  1. UVa 10048 Audiophobia【Floyd】

    题意:给出一个c个点,s条边组成的无向图,求一点到另一点的路径上最大权值最小的路径,输出这个值 可以将这个 d[i][j]=min(d[i][j],d[i][k]+d[k][j]) 改成 d[i][j ...

  2. 信息熵 Information Theory

    信息论(Information Theory)是概率论与数理统计的一个分枝.用于信息处理.信息熵.通信系统.数据传输.率失真理论.密码学.信噪比.数据压缩和相关课题.本文主要罗列一些基于熵的概念及其意 ...

  3. 这篇博客的内容基本没见过,mark 一下以后可以学习

    初识机器学习算法有哪些? 机器学习无疑是现在数据分析领域的一个重要内容,凡事从事IT工作领域的人都在平时的工作中或多或少的会用到机器学习的算法. 机器学习有很多算法,不过大的方面可分为两类:一个是学习 ...

  4. 【自动化测试】Selenium 下载文件

    用curl确定要下载的文件是什么类型的:另一种方法是使用requests 模块来查找内容类型 文件类型 http://tool.oschina.net/commons 1.先设置下载的目录,下载文件的 ...

  5. 模拟实现死亡之Ping(Ping of death)

    需求描述 使用hping构造IP分片,模拟实现死亡之Ping 环境搭建 使用VMWare和Dynamips. 实现思路 构造重装后大于65535字节的IP分片 hping 192.168.1.1 -1 ...

  6. hbase+hive应用场景

    一.Hive应用场景本文主要讲述使用 Hive 的实践,业务不是关键,简要介绍业务场景,本次的任务是对搜索日志数据进行统计分析.集团搜索刚上线不久,日志量并不大 .这些日志分布在 5 台前端机,按小时 ...

  7. EL表达式(胖先生版)

    EL表达式没有指定范围,从最小范围开始 <% pageContext.setAttribute("shxt", "java web"); request. ...

  8. [再寄小读者之数学篇](2014-11-26 广义 Schur 分解定理)

    设 $A,B\in \bbR^{n\times n}$ 的特征值都是实数, 则存在正交阵 $P,Q$ 使得 $PAQ$, $PBQ$ 为上三角阵.

  9. LR之错误处理

    1.脚本的健壮性 2.VuGen的处理机制 3.lr_continue_on_error函数 4.示例代码

  10. python27+django1.9创建app的视图及实现动态页面

    一.简易静态视图 views文件里写: from django.http import HttpResponse def hello(request): return HttpResponse(&qu ...