问题 A: 最大连续子序列
时间限制: 1 Sec 内存限制: 32 MB
提交: 422 解决: 185
[提交][状态][讨论版][命题人:外部导入]
题目描述
给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= K。最大连续子序列是所有连续子序列中元素和最大的一个,例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{ 11, -4, 13 },最大和为20。现在增加一个要求,即还需要输出该子序列的第一个和最后一个元素。
输入
测试输入包含若干测试用例,每个测试用例占2行,第1行给出正整数K( K<= 10000 ),第2行给出K个整数,中间用空格分隔,每个数的绝对值不超过100。当K为0时,输入结束,该用例不被处理。
输出
对每个测试用例,在1行里输出最大和、最大连续子序列的第一个和最后一个元素,中间用空格分隔。如果最大连续子序列不唯一,则输出序号i和j最小的那个(如输入样例的第2、3组)。若所有K个元素都是负数,则定义其最大和为0,输出整个序列的首尾元素。
样例输入
5 -3 9 -2 5 -4 3 -2 -3 -1 0
样例输出
12 9 5 0 -2 -1
提示
这是一道稍微有点难度的动态规划题。
首先可以想到的做法是枚举每个区间的和,预处理sum[i]来表示区间[1, i]的和之后通过减法我们可以O(1)时间获得区间[i, j]的和,因此这个做法的时间复杂度为O(n^2)。
然后这题的数据范围较大,因此还需作进一步优化才可以AC。记第i个元素为a[i],定义dp[i]表示以下标i结尾的区间的最大和,那么dp[i]的计算有2种选择,一种是含有a[i-1],一种是不含有a[i-1],前者的最大值为dp[i-1]+a[i],后者的最大值为a[i]。而两者取舍的区别在于dp[i-1]是否大于0。
#include<iostream>
using namespace std;
const int N=1e4+10;
int a[N],dp[N],Start[N];
int main(){
// freopen("input1.txt","r",stdin);
int n,Max,si,ei;//si是起点下标 ei是终点下标
while(cin>>n&&n!=0){
si=0,ei=n-1;
for(int i=0;i<n;i++){
cin>>a[i];
Start[i]=i;//开始所有的起点下标都设为自己
}
Max=dp[0]=a[0];
bool hasPos=false;
for(int i=1;i<n;i++){
if(dp[i-1]>=0){//起点下标i要最小 所以取等号
hasPos=true;
dp[i]=dp[i-1]+a[i];
Start[i]=Start[i-1];//起点变了
}else{
dp[i]=a[i];//Start[i]就是自己 以自己为起点
}
if(Max<dp[i]){
Max=dp[i];
ei=i;//更新终点
}
}
if(hasPos)//有正数
cout<<Max<<" "<<a[Start[ei]]<<" "<<a[ei]<<endl;
else cout<<0<<" "<<a[0]<<" "<<a[n-1]<<endl;
}
return 0;
}
问题 A: 最长上升子序列
时间限制: 2 Sec 内存限制: 64 MB
提交: 430 解决: 217
[提交][状态][讨论版][命题人:外部导入]
题目描述
一个数列ai如果满足条件a1 < a2 < ... < aN,那么它是一个有序的上升数列。我们取数列(a1, a2, ..., aN)的任一子序列(ai1, ai2, ..., aiK)使得1 <= i1 <i2 < ... < iK <= N。例如,数列(1, 7, 3, 5, 9, 4, 8)的有序上升子序列,像(1, 7), (3, 4, 8)和许多其他的子序列。在所有的子序列中,最长的上升子序列的长度是4,如(1, 3, 5, 8)。
现在你要写一个程序,从给出的数列中找到它的最长上升子序列。
输入
输入包含两行,第一行只有一个整数N(1 <= N <= 1000),表示数列的长度。
第二行有N个自然数ai,0 <= ai <= 10000,两个数之间用空格隔开。
输出
输出只有一行,包含一个整数,表示最长上升子序列的长度。
样例输入
7
1 7 3 5 9 4 8
样例输出
4
#include<iostream>
using namespace std;
const int N=1e3+10;
int a[N],dp[N];
int main(){
// freopen("input2.txt","r",stdin);
int n,max;
while(cin>>n){
for(int i=0;i<n;i++){
cin>>a[i];
}
max=0;
for(int i=0;i<n;i++){
dp[i]=1;
for(int j=0;j<i;j++){
if(a[j]<a[i]&&dp[j]+1>dp[i]){
dp[i]=dp[j]+1;
}
}
if(max<dp[i]) max=dp[i];
}
cout<<max<<endl;
}
return 0;
}
问题 A: 最长公共子序列
时间限制: 1 Sec 内存限制: 32 MB
提交: 355 解决: 199
[提交][状态][讨论版][命题人:外部导入]
题目描述
给你一个序列X和另一个序列Z,当Z中的所有元素都在X中存在,并且在X中的下标顺序是严格递增的,那么就把Z叫做X的子序列。
例如:Z=<a,b,f,c>是序列X=<a,b,c,f,b,c>的一个子序列,Z中的元素在X中的下标序列为<1,2,4,6>。
现给你两个序列X和Y,请问它们的最长公共子序列的长度是多少?
输入
输入包含多组测试数据。每组输入占一行,为两个字符串,由若干个空格分隔。每个字符串的长度不超过100。
输出
对于每组输入,输出两个字符串的最长公共子序列的长度。
样例输入
abcfbc abfcab programming contest abcd mnp
样例输出
4 2 0
#include<iostream>
#include<string>
#include <algorithm>
using namespace std;
const int N=100+10;
int a[N],dp[N][N];
int main(){
// freopen("input3.txt","r",stdin);
string s1,s2;
while(cin>>s1>>s2){
s1=" "+s1;
s2=" "+s2;
for(int i=0;i<s1.length();i++){
dp[i][0]=0;
}
for(int j=0;j<s2.length();j++){
dp[0][j]=0;
}
for(int i=1;i<s1.length();i++){
for(int j=1;j<s2.length();j++){
if(s1[i]==s2[j]){
dp[i][j]=dp[i-1][j-1]+1;//不要瞎写 abc acc (ab&ac)+1=2
}else{
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
}
//别忘记dp[i][j]的意义,直接输出dp[m][n]最长的两串即可 不必Max找最大
cout<<dp[s1.length()-1][s2.length()-1]<<endl;
}
return 0;
}
问题 A: 【字符串】最长回文子串
时间限制: 1 Sec 内存限制: 128 MB
提交: 255 解决: 122
[提交][状态][讨论版][命题人:外部导入]
题目描述
输入一个字符串,求出其中最长的回文子串。子串的含义是:在原串中连续出现的字符串片段。回文的含义是:正着看和倒着看相同。如abba和yyxyy。在判断回文时,应该忽略所有标点符号和空格,且忽略大小写,但输出应保持原样(在回文串的首部和尾部不要输出多余字符)。输入字符串长度不超过5000,且占据单独的一行。应该输出最长的回文串,如果有多个,输出起始位置最靠左的。
输入
一行字符串,字符串长度不超过5000。
输出
字符串中的最长回文子串。
样例输入
Confuciuss say:Madam,I'm Adam.
样例输出
Madam,I'm Adam
提示
样例说明:Madam,I'm Adam去掉空格、逗号、单引号、忽略大小写为MADAMIMADAM,是回文。
#include<iostream>
#include<string>
#include<cctype>
using namespace std;
string S;
const int N=5010;
char S1[N];
int Index[N];
int dp[N][N];
int main(){
// freopen("input4.txt","r",stdin);
int index,len,si,ei,max;
while(getline(cin,S)){
len=S.length();
index=0;
max=0;
for(int i=0;i<len;i++){
if(isalnum(S[i])){
S1[index]=tolower(S[i]);
Index[index]=i;//在原来字符串中的下标位置
index++;
}
}
//求S1最长回文子串
//边界
for(int i=0;i<index;i++){
dp[i][i]=1;
max=1;
if(i<index-1&&S1[i]==S1[i+1]){
dp[i][i+1]=1;
max=2;
}
}
//递归
for(int L=3;L<=index;L++){
for(int i=0;i+L-1<index;i++){
int j=i+L-1;
if(S1[i]==S1[j]){
dp[i][j]=dp[i+1][j-1];//不是长度 只是0 1代表true和false
}
if(dp[i][j]==1){//越来越长 j-i+1=L L递增
si=i,ei=j;
}
}
}
//输出
si=Index[si];ei=Index[ei];
cout<<S.substr(si,ei-si+1)<<endl;
}
return 0;
}