ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2021-07-25(动态规划)

2021-07-25 15:33:38  阅读:209  来源: 互联网

标签:25 07 int ll 矩阵 maxi 2021 include dp


链接:https://ac.nowcoder.com/acm/problem/15553
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
今天qwb要参加一个数学考试,这套试卷一共有n道题,每道题qwb能获得的分数为ai,qwb并不打算把这些题全做完,
他想选总共2k道题来做,并且期望他能获得的分数尽可能的大,他准备选2个不连续的长度为k的区间,
即[L,L+1,L+2,…,L+k-1],[R,R+1,R+2,…,R+k-1](R >= L+k)。
输入描述:

第一行一个整数T(T<=10),代表有T组数据
接下来一行两个整数n,k,(1<=n<=200,000),(1<=k,2k <= n)
接下来一行n个整数a1,a2,…,an,(-100,000<=ai<=100,000)

输出描述:

输出一个整数,qwb能获得的最大分数

示例1
输入
复制

2
6 3
1 1 1 1 1 1
8 2
-1 0 2 -1 -1 2 3 -1

输出
复制

6
7

这个题是一个dp加前缀和的题目。思想是用dp维护i点右边区间最大的连续的长度为k的子区间分值,这就要求维护的时候从右边开始,然后枚举当前节点,不断更新ans

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N=200005;
ll s[N];
ll maxi[N];
ll a[N];

int n,k;
int main(){
    int t;
    cin>>t;
    while(t--){
        cin>>n>>k;
        memset(a,0,sizeof(a));
        memset(maxi,-1e4,sizeof(maxi));
        memset(s,0,sizeof(s));
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            s[i]=s[i-1]+a[i];
        }
        for(int i=n-k+1;i>=1;i--){
            maxi[i]=max(maxi[i+1],s[i+k-1]-s[i-1]);
        }
        
        ll ans=-1e18;
        for(int i=k;i<=n-k;i++)
            ans=max(ans,s[i]-s[i-k]+maxi[i+1]);
        cout<<ans<<endl;
        
    }
    return 0;
}

链接:https://ac.nowcoder.com/acm/problem/20242
来源:牛客网

这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。
注意:选出的k个子矩阵 不能相互重叠。
输入描述:

第一行为n,m,k(1 ≤ n ≤ 100,1 ≤ m ≤ 2,1 ≤ k ≤ 10),
接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。

输出描述:

只有一行为k个子矩阵分值之和最大为多少。

示例1
输入
复制

3 2 2
1 -3
2 3
-2 3

输出
复制

9
这道题和上面一个有点类似,不过是根据数据范围我们设计一个
dp[i][j][k]表示第一列前i个,第二列前j个,选择k个子矩阵获得的最大值
那么实际上有四种情况。
由于要求不能重叠,我们维护方式就有所变化,但本质不会变

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;

const int N=105;
const int M=15;
int dp[N][N][M];
int sq[N][3];
int n,m,k;
int sum[N][3];//第j列前i项前缀和
int main(){
    cin>>n>>m>>k;
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=n;i++){//
        for(int j=1;j<=m;j++){
            scanf("%d",&sq[i][j]);
            sum[i][j]=sum[i-1][j]+sq[i][j];//维护前缀
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            for(int z=1;z<=k;z++){
                dp[i][j][z]=max(dp[i][j-1][z],dp[i-1][j][z]);
                for(int l=0;l<i;l++)
                    dp[i][j][z]=max(dp[l][j][z-1]+sum[i][1]-sum[l][1],dp[i][j][z]);
                for(int l=0;l<j;l++)
                    dp[i][j][z]=max(dp[i][l][z-1]+sum[j][2]-sum[l][2],dp[i][j][z]);
                if(i==j){//相等是特殊情况,前面的一般性的判断要继续执行
                  for(int l=0;l<i;l++)
                    dp[i][j][z]=max(dp[l][l][z-1]+sum[i][1]-sum[l][1]+sum[j][2]-sum[l][2],dp[i][j][z]);
                }
                
            }
        }
    }
    
    cout<<dp[n][n][k]<<endl;
    
    
    return 0;
}

上面两题的思想和我之前做的硬币组合思想很像,但硬币组合不涉及前缀和。

标签:25,07,int,ll,矩阵,maxi,2021,include,dp
来源: https://blog.csdn.net/weixin_52829980/article/details/119082282

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有