1007. Maximum Subsequence Sum (25)
Given a sequence of K integers { N1, N2, ..., NK }. A continuous subsequence is defined to be { Ni, Ni+1, ..., Nj } where 1 <= i <= j <= K. The Maximum Subsequence is the continuous subsequence which has the largest sum of its elements. For example, given sequence { -2, 11, -4, 13, -5, -2 }, its maximum subsequence is { 11, -4, 13 } with the largest sum being 20.
Now you are supposed to find the largest sum, together with the first and the last numbers of the maximum subsequence.
Input Specification:
Each input file contains one test case. Each case occupies two lines. The first line contains a positive integer K (<= 10000). The second line contains K numbers, separated by a space.
Output Specification:
For each test case, output in one line the largest sum, together with the first and the last numbers of the maximum subsequence. The numbers must be separated by one space, but there must be no extra space at the end of a line. In case that the maximum subsequence is not unique, output the one with the smallest indices i and j (as shown by the sample case). If all the K numbers are negative, then its maximum sum is defined to be 0, and you are supposed to output the first and the last numbers of the whole sequence.
Sample Input:10 -10 1 2 3 4 -5 -23 3 7 -21Sample Output:
10 1 4
#include<iostream>
#include<stdio.h>
using namespace std;
const int maxn=10010;
struct DP{
int start,end;
int data;
};
int main(){
int n,i;
cin>>n;
int num=0;
//while(n!=0){
DP dp[maxn];
int a[maxn];
for(i=0;i<n;i++){
cin>>a[i];
if(a[i]<0) num++;
}
if(num==n){
cout<<"0 "<<a[0]<<" "<<a[n-1]<<endl;
return 0;
}
dp[0].data=a[0];//dp[i]=max(dp[i-1]+a[i],a[i])
dp[0].end=dp[0].start=0;
for(i=1;i<n;i++){
if(dp[i-1].data+a[i]>a[i]){
dp[i].data=dp[i-1].data+a[i];
dp[i].start=dp[i-1].start;
dp[i].end=i;
}
else if(dp[i-1].data+a[i]<a[i]){
dp[i].data=a[i];
dp[i].start=dp[i].end=i;
}
else{
dp[i].data=a[i];
dp[i].start=dp[i].end=i;
}
}
int maxx=dp[0].data;
int j;
for(i=0;i<n;i++){
if(dp[i].data>maxx){
j=i;
maxx=dp[i].data;
}
}
printf("%d %d %d\n",maxx,a[dp[j].start],a[dp[j].end]);
//cin>>n;
//}
return 0;
}
问题 A: 最大连续子序列
时间限制: 1 Sec 内存限制: 32 MB 提交: 69 解决: 39[ 提交][ 状态][ TK题库][命题人: ]题目描述
给定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。
//问题A: 最大和连续子序列
#include<stdio.h>
#include<iostream>
using namespace std;
struct SUM{
int start,end;
int data;
};
int main(){
int n,i;
cin>>n;
while(n!=0){
int num=0;
int a[10010];
SUM dp[10010];
for(i=0;i<n;i++){
cin>>a[i];
if(a[i]<0) num++;
}
if(num==n){
cout<<"0 "<<a[0]<<" "<<a[n-1]<<endl;
}
else{
dp[0].data=a[0];
dp[0].start=dp[0].end=0;
for(i=1;i<n;i++){
if(a[i]+dp[i-1].data>=a[i]){
dp[i].data=a[i]+dp[i-1].data;
dp[i].start=dp[i-1].start;
dp[i].end=i;
}
else{
dp[i].data=a[i];
dp[i].start=dp[i].end=i;
}
}
int maxx=dp[0].data;
int j=0;
for(i=1;i<n;i++){
//cout<<"i:"<<i<<"dp[i]:"<<dp[i].data<<endl;
if(dp[i].data>maxx){
maxx=dp[i].data;
j=i;
}
}
printf("%d %d %d\n",dp[j].data,a[dp[j].start],a[dp[j].end]);
}
cin>>n;
}
return 0;
}
问题 A: 最长上升子序列
时间限制: 2 Sec 内存限制: 64 MB提交: 73 解决: 51
[ 提交][ 状态][ TK题库][命题人:]
题目描述
一个数列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,两个数之间用空格隔开。
输出
输出只有一行,包含一个整数,表示最长上升子序列的长度。
样例输入
71 7 3 5 9 4 8
样例输出
4
//问题A: 最长上升子序列
#include<stdio.h>
#include<iostream>
using namespace std;
int main(){
int n;
int buf[1010];
int dp[1010]={0};
cin>>n;
int i,j;
for(i=0;i<n;i++){
cin>>buf[i];
}
int ans=-1;
for(i=0;i<n;i++){
dp[i]=1;
for(j=0;j<i;j++){
if(buf[j]<=buf[i]&&dp[j]+1>dp[i]){
dp[i]=dp[j]+1;
}
}
ans=ans>dp[i]?ans:dp[i];
}
printf("%d",ans);
return 0;
}
问题 A: 最长公共子序列
时间限制: 1 Sec 内存限制: 32 MB提交: 63 解决: 49
[ 提交][ 状态][ TK题库][命题人: ]
题目描述
例如:Z=<a,b,f,c>是序列X=<a,b,c,f,b,c>的一个子序列,Z中的元素在X中的下标序列为<1,2,4,6>。
现给你两个序列X和Y,请问它们的最长公共子序列的长度是多少?
输入
输出
样例输入
abcfbc abfcab
programming contest
abcd mnp
样例输出
4
2
0
//问题A: 最长公共子序列
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
int max(int a,int b){
return a>b?a:b;
}
int main(){
char a[110],b[110];
while(scanf("%s %s",a,b)!=EOF){
int i,j;
int dp[110][110];
int len1=strlen(a);
int len2=strlen(b);
char aa[110],bb[110];
for(i=0;i<len1;i++){
aa[i+1]=a[i];
}
for(i=0;i<len2;i++){
bb[i+1]=b[i];
}
for(i=0;i<=len1;i++){
dp[i][0]=0;
}
for(i=0;i<=len2;i++){
dp[0][i]=0;
}
for(i=1;i<=len1;i++){
for(j=1;j<=len2;j++){
if(aa[i]==bb[j]){
dp[i][j]=dp[i-1][j-1]+1;
}
else{
dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
}
}
}
printf("%d\n",dp[len1][len2]);
}
return 0;
}
问题 A: 【字符串】最长回文子串
时间限制: 1 Sec 内存限制: 128 MB提交: 43 解决: 24
[ 提交][ 状态][ TK题库][命题人: ]
题目描述
输入一个字符串,求出其中最长的回文子串。子串的含义是:在原串中连续出现的字符串片段。回文的含义是:正着看和倒着看相同。如abba和yyxyy。在判断回文时,应该忽略所有标点符号和空格,且忽略大小写,但输出应保持原样(在回文串的首部和尾部不要输出多余字符)。输入字符串长度不超过5000,且占据单独的一行。应该输出最长的回文串,如果有多个,输出起始位置最靠左的。
输入
一行字符串,字符串长度不超过5000。
输出
字符串中的最长回文子串。
样例输入
Confuciuss say:Madam,I'm Adam.
样例输出
Madam,I'm Adam
//问题A: 【字符串】最长回文子串
//去掉空格、标点、大小写,判断回文
//输出原文
#include<stdio.h>
#include<string.h>
struct STR{
char a;
int no;
}str[5010];
int dp[5010][5010];
int deal(char &a){
if(a>='0'&&a<='9') return 1;
if(a>='a'&&a<='z'){
a=a-'a'+'A';
return 1;
}
if(a>='A'&&a<='Z') return 1;
return 0;
}
int main(){
memset(dp,0,sizeof(dp));
char buf[5010];
gets(buf);
int len=strlen(buf);
int i,j=0,k;
for(i=0;i<len;i++){//只保留字母和数字,同时将小写转换为大写
char a=buf[i];
if(deal(a)==1){
str[j].a=a;
str[j].no=i;//原来的位置
j++;
}
}
int len2=j;//需要判断的字符串的长度
int ans=1;//当前回文串长度
int begin=0;
for(i=0;i<len2;i++){
dp[i][i]=1;
if(i<len2-1){
if(str[i].a==str[i+1].a){
dp[i][i+1]=1;
if(ans!=2) begin=i;//第一次更新
ans=2;
}
}
}
for(int L=3;L<=len2;L++){
for(i=0;i+L-1<len2;i++){
j=i+L-1;
if(dp[i+1][j-1]==1&&str[i].a==str[j].a){
dp[i][j]=1;
if(ans!=L) begin=i;//L长度的第一次更新
ans=L;
}
}
}
//printf("%d %d\n",begin,ans);
//printf("%d %d\n",str[begin].no,str[begin+ans-1].no);
for(i=str[begin].no;i<=str[begin+ans-1].no;i++){
printf("%c",buf[i]);
}
return 0;
}
1040. Longest Symmetric String (25)
Given a string, you are supposed to output the length of the longest symmetric sub-string. For example, given "Is PAT&TAP symmetric?", the longest symmetric sub-string is "s PAT&TAP s", hence you must output 11.
Input Specification:
Each input file contains one test case which gives a non-empty string of length no more than 1000.
Output Specification:
For each test case, simply print the maximum length in a line.
Sample Input:Is PAT&TAP symmetric?Sample Output:
11
#include<stdio.h>
#include<string>
#include<iostream>
#include<sstream>
#include<string.h>
using namespace std;
int dp[1001][1001];
int main(){
string str;
getline(cin,str);
memset(dp,0,sizeof(dp));
int i;
int ans=1;
for(i=0;i<str.size();i++){
dp[i][i]=1;
if(i<str.size()-1){
if(str[i]==str[i+1]){
dp[i][i+1]=1;
ans=2;
}
}
}
int L;
for(L=3;L<=str.size();L++){
for(i=0;i+L-1<str.size();i++){
int j=i+L-1;
if(str[i]==str[j]&&dp[i+1][j-1]==1){
dp[i][j]=1;
ans=L;
}
}
}
printf("%d",ans);
return 0;
}
1045. Favorite Color Stripe (30)
Eva is trying to make her own color stripe out of a given one. She would like to keep only her favorite colors in her favorite order by cutting off those unwanted pieces and sewing the remaining parts together to form her favorite color stripe.
It is said that a normal human eye can distinguish about less than 200 different colors, so Eva's favorite colors are limited. However the original stripe could be very long, and Eva would like to have the remaining favorite stripe with the maximum length. So she needs your help to find her the best result.
Note that the solution might not be unique, but you only have to tell her the maximum length. For example, given a stripe of colors {2 2 4 1 5 5 6 3 1 1 5 6}. If Eva's favorite colors are given in her favorite order as {2 3 1 5 6}, then she has 4 possible best solutions {2 2 1 1 1 5 6}, {2 2 1 5 5 5 6}, {2 2 1 5 5 6 6}, and {2 2 3 1 1 5 6}.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (<=200) which is the total number of colors involved (and hence the colors are numbered from 1 to N). Then the next line starts with a positive integer M (<=200) followed by M Eva's favorite color numbers given in her favorite order. Finally the third line starts with a positive integer L (<=10000) which is the length of the given stripe, followed by L colors on the stripe. All the numbers in a line are separated by a space.
Output Specification:
For each test case, simply print in a line the maximum length of Eva's favorite stripe.
Sample Input:6 5 2 3 1 5 6 12 2 2 4 1 5 5 6 3 1 1 5 6Sample Output:
7
//最长不下降子序列解法
#include<stdio.h>
#include<iostream>
using namespace std;
const int maxn=100010;
int hhash[201];//为个可能喜欢的颜色建hash
int buf[maxn];
int dp[maxn];
int main(){
int n,m,i;
cin>>n;//color编号-n
for(i=0;i<201;i++) hhash[i]=-1;
cin>>m;
for(i=0;i<m;i++){
int a;
cin>>a;
hhash[a]=i;
}
cin>>m;
int j=0,k;
for(i=0;i<m;i++){
int a;
cin>>a;
if(hhash[a]!=-1) buf[j++]=hhash[a];//只筛选出喜欢的,并且转化为hash值
}
int ans=-1;
for(i=0;i<j;i++){
dp[i]=1;
for(k=0;k<i;k++){
if(buf[k]<=buf[i]&&dp[k]+1>dp[i]){
dp[i]=dp[k]+1;
}
}
ans=ans>dp[i]?ans:dp[i];
}
printf("%d",ans);
return 0;
}
//最长不下降子序列解法
#include<stdio.h>
#include<iostream>
using namespace std;
const int maxn=100010;
int buf[maxn];
int dp[201][maxn];
int a[201]={0};
int b[maxn];
int main(){
int n,m1,m2,j,i;
cin>>n;//color编号-n
cin>>m1;
for(i=1;i<=m1;i++){
cin>>a[i];
}
cin>>m2;
for(i=1;i<=m2;i++){
cin>>b[i];
}
for(i=0;i<=m1;i++) dp[i][0]=0;
for(i=0;i<=m2;i++) dp[0][i]=0;
for(i=1;i<=m1;i++){
for(j=1;j<=m2;j++){
if(a[i]==b[j]){
dp[i][j]=max(dp[i-1][j],dp[i][j-1])+1;
}
else{
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
}
printf("%d",dp[m1][m2]);
return 0;
}
问题 A: 矩形嵌套
时间限制: 1 Sec 内存限制: 64 MB提交: 23 解决: 19
[ 提交][ 状态][ TK题库][命题人: ]
题目描述
输入
每组测试数据的第一行是一个正正数n,表示该组测试数据中含有矩形的个数(n<=1000)
随后的n行,每行有两个数a,b(0<a,b<100),表示矩形的长和宽
输出
样例输入
1
10
1 2
2 4
5 8
6 10
7 9
3 1
5 8
12 10
9 7
2 2
样例输出
5
//问题A: 矩形嵌套
//若最长路径长度相同,选择字典序小的那个
//依次根据输入长宽判断能否嵌套
#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
int dp[1010];
int G[1010][1010];
int choice[1010];
struct node{
int a,b;
};
bool qiantao(node t1,node t2){
if(t1.a<t2.a&&t1.b<t2.b) return true;
if(t1.a<t2.b&&t1.b<t2.a) return true;
return false;
}
int DP(int i,int m){//m是顶点数
if(dp[i]>0) return dp[i];
for(int j=0;j<m;j++){
if(G[i][j]!=-1){
int temp=DP(j,m)+G[i][j];
if(temp>dp[i]){
dp[i]=temp;
choice[i]=j;
}
}
}
return dp[i];
}
int print(int i){//先要得到最大的dp[i]
//printf("%d",i);
int num=1;
while(choice[i]!=-1){
i=choice[i];num++;
//printf("->%d",i);
}
return num;
}
int main(){
int n,i,j,k;
cin>>n;
for(i=0;i<n;i++){
node buf[1010];
memset(dp,0,sizeof(dp));
memset(G,-1,sizeof(G));
memset(choice,-1,sizeof(choice));
int m;
cin>>m;
for(j=0;j<m;j++){
int a,b;
cin>>a>>b;
buf[j].a=a;
buf[j].b=b;
}
for(j=0;j<m;j++){
for(k=j+1;k<m;k++){
if(qiantao(buf[j],buf[k])) G[j][k]=1;//j->k
else if(qiantao(buf[k],buf[j])) G[k][j]=1;//k->j
}
}
int max=-1;
int u=-1;
for(j=m-1;j>=0;j--){//字典序
dp[j]=DP(j,m);
if(dp[j]>max){
max=dp[j];
u=j;
}
}
int num=print(u);
printf("%d\n",num);
}
return 0;
}