区间和
Description
金金最喜欢做有挑战的事情了,比如说求区间最大子段和。
一开始,金金有n个数,第i个数字是ai。
金金又找来了一个新的数字P,并想将这n个数字中恰好一个数字替换成P。要求替换后的最大子段和尽可能大。
金金知道这个题目仍然很简单,所以如果你做不出来,金金就要和你谈一谈了。
注:最大子段和是指在n个数中选择一段区间[L,R](L<=R)使得这段区间对应的数字之和最大。
Input
第一行两个数n,P。
接下来一行n个数ai。
Output
一个数表示答案。
Sample Input
5 3
-1 1 -10 1 -1
Sample Output
5
More Info
样例说明:将第三个数变成3后最大子段和为[2,4]。
数据范围:n<=1000,-1000<=ai,P<=1000。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int dp[1001][2]={0},i,j,n,x,a[10001],ans=-999999999,p;
cin>>n>>p;
for(i=1;i<=n;i++)
{
cin>>x;
dp[i][0]=max(dp[i-1][0]+x,x);//为下一步做铺垫
dp[i][1]=max(p,max(dp[i-1][0]+p,dp[i-1][1]+x));
ans=max(ans,dp[i][1]);
}
cout<<ans<<endl;
return 0;
}
[蓝桥杯][历届试题]最大子阵
Description
给定一个n*m的矩阵A,求A中的一个非空子矩阵,使这个子矩阵中的元素和最大。
其中,A的子矩阵指在A中行和列均连续的一块。
Input
输入的第一行包含两个整数n, m,分别表示矩阵A的行数和列数。(1 ≤ n, m ≤ 500)
接下来n行,每行m个整数,表示矩阵A。
Output
输出一行,包含一个整数,表示A中最大的子矩阵中的元素和。
Sample Input
3 3
-1 -4 3
3 4 -1
-5 -2 8
Sample Output
10
More Info
WA?你考虑矩阵内全为负的情况了么
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long i,k,j,n,m,dp[501][501]={0},t,ans=INT_MIN,sum;
cin>>n>>m;
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
{
cin>>t;
dp[i][j]=dp[i-1][j]+t;//前i行的j列的和
}
}
for(i=1;i<=n;i++)//二维转换为一维
{
for(j=1;j<=i;j++)//1到1->1到n行
{
sum=0;
for(k=1;k<=m;k++)
{
sum+=dp[i][k]-dp[j-1][k];//前i行的k列-前j-1行的k列 ,减一是因为最少得有一行
ans=max(ans,sum);
if(sum<0) sum=0;//舍弃k列的前边
}
}
}
cout<<ans<<endl;
return 0;
}
最长上升子序列
Description
给定一长度为n的数列,数列中的每个数都在1~100000之间
请在不改变原数列顺序的前提下,从中取出一定数量的整数(不需要连续),并使这些整数构成单调上升序列。
输出这类单调上升序列的最大长度。
Input
输入包括两行,第一行为n,代表数列的长度。(1 ≤ n ≤ 100000)
第二行为n个整数。
Output
输出这类单调上升序列的最大长度
Sample Input
5
3 1 5 4 6
Sample Output
3
More Info
对于样例的解释:356,156,146 均可组成长度为3的上升子序列
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,a[100001],tot=0,s[100001],i,num;
cin>>n;
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
s[++tot]=a[1];
for(i=1;i<=n;i++)
{
if(s[tot]<a[i])
s[++tot]=a[i];
else
{
num=lower_bound(s+1,s+tot+1,a[i])-s; //lower_bound二分查找
s[num]=a[i];
}
}
printf("%d\n",tot);
return 0;
}
过河卒
Description
大三老学长ZHB平时喜欢边晒晒太阳边下象棋养养老,有一天他突然想到了这么一个问题:
棋盘上AA点有一个过河卒,需要走到目标BB点。卒行走的规则:可以向下、或者向右。同时在棋盘上CC点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,AA点(0, 0)(0,0)、BB点(n, m)(n,m)(nn, mm为不超过2020的整数),同样马的位置坐标是需要给出的(假设马的位置不会在距离棋盘边缘两格范围内)。
现在ZHB学长要求你计算出卒从AA点能够到达BB点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
Input
一行四个数据,分别表示BB点坐标和马的坐标。
Output
一个数据,表示所有的路径条数。
Sample Input
6 6 3 3
Sample Output
6
More Info
结果可能很大!
#include<bits/stdc++.h>
using namespace std;
long long mx,my,ux,uy,dp[101][101],book[101][101],d[8][2]={2,1,2,-1,1,2,1,-2,-1,2,-1,-2,-2,1,-2,-1};
int main()
{
int i,j;
cin>>ux>>uy>>mx>>my;
book[mx+1][my+1]=1;
for(i=0;i<8;i++)
if(mx+d[i][0]>=0&&mx+d[i][0]<=ux&&my+d[i][1]>=0&&my+d[i][1]<=uy)
book[mx+d[i][0]+1][my+d[i][1]+1]=1;
dp[1][1]=1;//防止数组下标为负,集体加一右移
for(i=1;i<=ux+1;i++)
for(j=1;j<=uy+1;j++)
{
if(i==1&&j==1);
else
{
if(book[i-1][j]==0)
dp[i][j]+=dp[i-1][j];
if(book[i][j-1]==0)
dp[i][j]+=dp[i][j-1];
}
}
cout<<dp[ux+1][uy+1]<<endl;
return 0;
}
搬砖
Description
Sam暑假找了个搬砖的活儿,每天12个小时内有1~8种转可以搬,每种的时间的工资都不一样(如搬第一种砖的时间为0时~4时,工资为5元,搬第二种砖的时间为2时~6时,工资为8元),每次搬砖必须搬完才能搬下一次转(即不可重叠,如上例中搬第一种砖就不能搬第二种转),请你帮Sam拿拿主意,怎样安排可以赚到最多的工资?
Input
输入包含八组(八种砖),每组包含三个整数:搬砖开始时间s1、结束时间s2与工资sal。(0 <= s1 < 11 , 0 < s2 <= 11 , 1 <= sal <= 10)。
Output
Sam12小时内最多可以赚到的工资。
Sample Input
3 5 1
1 4 5
0 6 8
4 7 4
3 8 6
5 9 3
6 10 2
8 11 4
Sample Output
13
More Info
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int f[17][19]={0},x,y,g;
for(int i=0;i<8;i++)
{
cin>>x>>y>>g;
f[x][y]=g;
}
for(int i=1;i<=12;i++)//区间长度
for(int j=0;j<12-i;j++)//头
{
int k=i+j;//尾
for(int t=j;t<k;t++)//过渡
f[j][k]=max(f[j][k],f[j][t]+f[t][k]);
}
cout<<f[0][11]<<endl;
return 0;
}
最长公共子序列
Description
给定两个序列 X={x1,x2,…,xm} 和 Y={y1,y2,…,yn},找出X和Y的最长公共子序列。
Input
输入数据有多组,每组有两行 ,每行为一个长度不超过500的字符串(输入全是小写英文字母),表示序列X和Y。
Output
每组输出一行,表示所求得的最长公共子序列的长度,若不存在公共子序列,则输出0。
Sample Input
abcbdab
bdcaba
Sample Output
4
More Info
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
string a,b;
int dp[1001][1001];
int main()
{
while(cin>>a>>b)
{
memset(dp,0,sizeof(dp));
for(int i=1;i<=a.size();i++)
for(int j=1;j<=b.size();j++)
{
if(a[i-1]==b[j-1])
dp[i][j]=dp[i-1][j-1]+1;
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
cout<<dp[a.size()][b.size()]<<endl;
}
return 0;
}