1(最大子段和)
题目描述 :
给出一段序列,选出其中连续且非空的一段使得这段和最大。
输入格式:
第一行是一个正整数N,表示了序列的长度。
第二行包含N个绝对值不大于1e9的整数Ai,描述了这段序列。
输出格式:
一个整数,为最大的子段和是多少。
思路:
对于全部为负数的序列 ,我们只需输出一个最大值即可。
对于不全为负数的序列 ,我们利用前缀和sum处理,每次更新一个最大值max,当sun<0时,说明后面的数加上此前缀无法变得更大,和则令sun=0,继续处理。
代码:
#include
long long n,a[1000005],sum,max,MAX=-1e9;
int main()
{
scanf("%lld",&n);
for(int i=0;i<n;i++)
{
scanf("%lld",&a[i]);
if(a[i]>MAX)
MAX=a[i];
}
if(MAX<=0)
{
printf("%lld",MAX);
return 0;
}
max=a[0];
for(int i=0;i<n;i++)
{
sum+=a[i];
if(sum<0)
sum=0;
if(sum>max)
max=sum;
}
printf("%lld",max);
return 0;
}
2 (最大子矩阵和)
题目描述 :
给出一个矩阵,求最大非空子矩阵是多少。
输入格式:
第一行是正整数N ,M,表示矩阵的行数 列数。
接下来N行,每行M个数,表示-1e9<=a[i][j]<=1e9。
输出格式:
一个整数,为最大的非空子矩阵和是多少。
思路:我们可以把二维的矩阵,转变为一维的子段和问题处理,所以我们要储存a[i][j]第j列前i行和。
代码:
#include
long long n,m,a[444][444],b[444][444],s,ans=-1e9;
int main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%lld",&a[i][j]);
b[i][j]=b[i-1][j]+a[i][j];
if(ans<a[i][j])
ans=a[i][j];
}
}
if(ans<=0)
{
printf("%lld",ans);
return 0;
}
else
{
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
s=0;
for(int k=1;k<=m;k++)
{
s+=b[j][k]-b[i][k];
if(s<0)
s=0;
else if(s>ans)
ans=s;
}
}
}
}
printf("%lld",ans);
return 0;
}
1.( 跳木桩)
面前有一排 n 个木桩,木桩的高度分别是h1,h2,h3⋯hn。第一步可以跳到任意一个木桩,接下来的每一步不能往回跳只能往前跳,并且跳下一个木桩的高度 不大于 当前木桩。希望能踩到尽量多的木桩,请你计算,最多能踩到多少个木桩。
输入格式
第一行输入一个整数 n代表木桩个数。第二行输入 n个整数 分别代表 n 个木桩的高度。(1≤n≤1000,1≤hi≤100000)
输出格式
输出一个整数,代表最多能踩到的木桩个数,占一行。
样例输入
6
3 6 4 1 4 2
样例输出
4
思路:本题的模版是最长不上升子序列,dp[i]表示以第i号元素为结尾的子序列,最长是多少。我们只需要枚举i号之前的元素,有多少不小于h[i]即可。最后输出最大的一个dp[i].
代码:
#include
int n,h[100005],dp[100005],ans=1;
int max(int x,int y)
{
return x>y?x:y;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&h[i]);
}
for(int i=1;i<=n;i++)
{
dp[i]=1;
for(int j=1;j<i;j++)
{
if(h[j]>=h[i])
{
dp[i]=max(dp[j]+1,dp[i]);
ans=max(dp[i],ans);
}
}
}
printf("%d",ans);
return 0;
}
2(删除最少元素) 思路:两个dp 代码: 3(优化版本的最长上升子序列) 输入格式 第二行包含N个整数,表示完整序列。 输出格式 数据范围 思路:考虑到上述最长子序列算法时间复杂度为n方,而本题n的范围为1e5,所以必须进行优化。 这样当我们遍历完整个数组a后就可以得到最终的结果。 时间复杂度分析:O(nlogn) 代码: 1(最长公共子序列) 我们使用dp[i][j]来表示第一个串的前i位和第二个串的前j位中的最长公共子序列,我们很容易能发现当两个串的任意一个串的当前长度为0时,它的最长公共子序列的长度为0,所以先对dp数组的边界进行初始化。然后我们发现,如果a[i]=b[j],dp[i][j]=dp[i-1][j-1]+1,很显然,当比对的位字符一样时,能得到该状态转移方程。如果a[i]≠b[j],dp[i][j]=max(dp[i-1][j],dp[i][j-1]),该状态转移方程是由上面的2,3条取最大值得到的。 代码: 2 思路: 代码: 1 小沐沐先让奶牛研究了最长上升子序列,再让他们研究了最长公共子序列,现在又让他们研究最长公共上升子序列了。 小沐沐说,对于两个数列A和B,如果它们都包含一段位置不一定连续的数,且数值是严格递增的,那么称这一段数是两个数列的公共上升子序列,而所有的公共上升子序列中最长的就是最长公共上升子序列了。 奶牛半懂不懂,小沐沐要你来告诉奶牛什么是最长公共上升子序列。 不过,只要告诉奶牛它的长度就可以了。 数列A和B的长度均不超过3000。 输入格式 第二行包含N个整数,表示数列A。 第三行包含N个整数,表示数列B。 输出格式 数据范围 思路:dp[i][j]表示a中前i位和b中第j位的最长公共上升子序列。对于a[i],我们遍历b中每个元素,判断a[i]和b[j]的关系,如果a[i]>b[j],那么为了方便后面找到a[i]=b[k]时,dp[i][k]的最长公共子序列,我们记录最大的max=dp[i-1][j](a[i]>b[j])。如果a[i]=b[j],那么dp[i][j]=max+1. 代码: 2 输入格式 接下来一行输入n个整数,a1,a2,a3⋯an,代表第一份记录的n个时间戳。(1≤ai≤103) 接下来一行输入m个整数,b1,b2,b3⋯bm,代表第二份记录的m个时间戳。(1≤bi≤103) 输出格式 输入样例 代码: 编辑距离参考思路 每个人都有点秘密,蒜头君也不例外,他把秘密记在一个小本上,并且留有备份,不过第一个本的内容被人破坏掉了,跟原来不一定相同了,他现在想要照着第二个本把第一个本的内容还原,每一次做一个操作,一个操作可以是在某位置增加一个字符,删掉某个字符,或者把某个位置的字符改成另一个字符,他想知道他最少需要进行多少次操作才能把第一个本的内容还原。 输入格式 第二行一个字符串B,表示第二个本上面的字符串。 字符串均仅有小写字母组成且长度均不超过1000。 输出格式 样例输入 代码:
给定n个数 ,满足a[i]>=a[j]···>=a[k]<=···a[p]<=a[q] (其中 i#include
给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少。
第一行包含整数N。
输出一个整数,表示最大长度。
1≤N≤100000,
−109≤数列中的数≤109
输入样例:
7
3 1 2 1 8 5 6
输出样例:
4
首先数组a中存输入的数(原本的数),开辟一个数组f用来存结果,最终数组f的长度就是最终的答案;假如数组f现在存了数,当到了数组a的第i个位置时,首先判断a[i] > f[cnt] ? 若是大于则直接将这个数添加到数组f中,即f[++cnt] = a[i];这个操作时显然的。
当a[i] <= f[cnt] 的时,我们就用a[i]去替代数组f中的第一个大于等于a[i]的数,因为在整个过程中我们维护的数组f 是一个递增的数组,所以我们可以用二分查找在 logn 的时间复杂的的情况下直接找到对应的位置,然后替换,即f[l] = a[i]。
我们用a[i]去替代f[i]的含义是:以a[i]为最后一个数的严格单调递增序列,这个序列中数的个数为l个。#include
最长公共子序列
思路:
设X=x1 x2…xm和Y=y1 y2…yn是两个序列,Z=z1 z2…zk是这两个序列的一个最长公共子序列。
#include
问题描述
一个字符串如果从左往右读和从右往左读都一样,那么这个字符串是一个回文串。例如:”abcba”,”abccba”。
蒜头君想通过添加字符把一个非回文字符串变成回文串。例如:”trit”,可以添加一个’i’ 变成回文串”tirit”。请你用程序计算出,对于一个给定的字符串,最少需要添加几个字符,才能变成回文串。
输入格式
输入一个长度为n(1≤n≤3000) 的字符串。(字符串只包含字母)
输出格式
输出最少需要添加的字符个数,占一行。
简单分析一些就可以发现:既然是回文串,那么将原串s1倒置得到一个新的字符串s2,求出s1和s2的最长公共子序列长度,用s1的长度减去所求长度就是最少添加字符数量。#include
最长公共上升子序列
熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目。
第一行包含一个整数N,表示数列A,B的长度。
输出一个整数,表示最长公共子序列的长度。
1≤N≤3000,序列中的数字均不超过231−1
输入样例:
4
2 2 1 3
2 1 2 3
输出样例:
2#include
蒜头君喜欢把做过的事情记录下来,写在日志里,为了安全起见,它还有一份备份放在另外的地方,不过很不幸的是,最近他的两份日志都受到了破坏,有增加删除修改,但没有改变任何原来的顺序,两份受到的破坏不一定一样,蒜头君记录事情都是按时间顺序的,记录的也都是时间戳,所以正确的记录上时间戳肯定是严格递增的,并且只有两份记录上都出现了的时间戳他才认为有可能自己做了,现在他想知道他最多可能做了多少事情。
第一行输入两个整数n,m代表两份记录的长度。(1≤n,m≤103)
输出一个整数,代表蒜头君最多可能做了多少事情。
3 2
1 3 2
1 2
输出样例
2#include
编辑距离
第一行一个字符串A,表示第一个本被破坏之后的字符串。
输出一个整数,为蒜头君最少要做的操作数。
aa
ab
样例输出
1#include