HDU 1024 Max Sum Plus Plus(m子段最大和)
-
题意: 给 n 个数,将其分为 m 段,各段之间不能有交叉重叠,每一段的值代表段中所有数的和,求最大值。
-
思路: dp[i][j]表示前j个数分为i部分的最大和,则状态转移方程为 dp[i][j] = max(dp[i][j-1] + a[j], dp[i-1][k] + a[j]) 0 < k < j 。前者是将第 j 个数加入到第i部分,后者是将第 j 个数做为第 i 部分的第一个数。
但这样的时间复杂度是O(n^3),会TLE,所以得优化。
dp[j] 数组表示前 j 个数分成当前 i 部分的最大值
mav[j] 数组表示第 j 层的最大值
状态转移方程为 dp[j] = max(dp[j-1]+a[j], mav[j-1]+a[j]);
Code:
#include <iostream>
#include <cstring>
#define inf 0x3f3f3f3f
using namespace std;
const int N=1e6+100;
int a[N],dp[N],Max[N];
int main(){
int m,n;
while(cin>>m>>n){
memset(dp,0,sizeof(dp));
memset(Max,0,sizeof(Max));
for(int i=1;i<=n;i++)
cin>>a[i];
int maxn;
for(int i=1;i<=m;i++){
maxn=-inf;
for(int j=i;j<=n;j++){ //j不能小于i
dp[j]=max(dp[j-1]+a[j],Max[j-1]+a[j]);
Max[j-1]=maxn; //maxn表示上一层的最大值
maxn=max(maxn,dp[j]);
}
}
cout<<maxn<<endl;
}
return 0;
}
HDU 1257 最少拦截系统(LIS)
-
题意: 导弹系统拦截的炮弹不能比前一个高,那么每一个导弹系统拦截的炮弹就是最长不上升序列,问最少需要多少的导弹系统,其实就是求最长递增子序列长度。
-
思路: LIS裸题。
Code:
#include <iostream>
#include <cstring>
using namespace std;
const int N=1e6+100;
int a[N],dp[N];
int main(){
int n;
while(cin>>n){
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
cin>>a[i];
dp[i]=1;
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
if(a[j]<a[i])
dp[i]=max(dp[i],dp[j]+1);
}
ans=max(ans,dp[i]);
}
cout<<ans<<endl;
}
}