Kuangbin专题12 基础DP

Posted 鱼竿钓鱼干

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kuangbin专题12 基础DP相关的知识,希望对你有一定的参考价值。

Kuangbin专题12 基础DP

讲解视频链接(制作中),如果是板子题目就不讲了
个人觉得有点意思的题目:A,D,K,M,O,Q,S

A - Max Sum Plus Plus

「题意」
你有n个数s1, s2…sn,给你一个整数m,求m个子段和的最大值

「代码」

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

typedef long long LL;
const int N=1e6+10;
LL s[N],lastmax[N];
LL f[N];

int main(){
    int n,m;
    while(~scanf("%d%d",&m,&n)){
        for(int i=1;i<=n;i++)scanf("%lld",&s[i]);
        //f[i][j]=max(f[i][j-1],f[i-1][j-1],f[i-1][j-2],f[i-1][j-3],……f[i-1][i-1]);
        memset(f,0,sizeof f);f[0]=-1e9;
        memset(lastmax,0,sizeof lastmax);
        LL mmax;
        for(int i=1;i<=m;i++){//分成i组
            mmax=-1e9;
            for(int j=i;j<=n;j++){
                f[j]=max(f[j-1],lastmax[j-1])+s[j];
                lastmax[j-1]=mmax;
                mmax=max(mmax,f[j]);
            }
        }
        printf("%lld\\n",mmax);
    }    

    return 0;
}

B - Ignatius and the Princess IV

「题意」
找出现次数最多的数
「代码」

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

typedef long long LL;
const int N=1e6+10;

map<LL,int>mp;

int main(){
    int n;
    while(~scanf("%d",&n)){
        LL ans=0;
        mp.clear();
        int maxcnt=0;
        for(int i=1;i<=n;i++){
            LL x;scanf("%lld",&x);
            mp[x]++;
            if(mp[x]++>maxcnt){
                maxcnt=mp[x];
                ans=x;
            }
        }
        printf("%lld\\n",ans);
    }
    return 0;
}

C - Monkey and Banana

「题意」
有n种类型的砖块,每种类型的砖块都有无限个。第i块砖块的长宽高分别用xi,yi,zi来表示。 同时,由于砖块是可以旋转的,每个砖块的3条边可以组成6种不同的长宽高。在构建塔时,当且仅当A砖块的长和宽都分别小于B砖块的长和宽时,A砖块才能放到B砖块的上面,因为必须留有一些空间让猴子来踩。

「代码」

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

typedef long long LL;
const int N=5e3+10;

struct cobe{
    LL x,y,z;
}c[N];
LL f[N];
int Case;
bool cmp(cobe A,cobe B){
    if(A.x!=B.x)return A.x>B.x;
    if(A.y!=B.y)return A.y>B.y;
    return 0;
}
int main(){
    int n;
    while(~scanf("%d",&n)&&n){
        Case++;
        LL ans=0,cnt=0,xx,yy,zz;
        for(int i=1;i<=n;i++){
            scanf("%lld%lld%lld",&xx,&yy,&zz);
            c[cnt+1]={xx,yy,zz};
            c[cnt+2]={xx,zz,yy};
            c[cnt+3]={yy,xx,zz};
            c[cnt+4]={yy,zz,xx};
            c[cnt+5]={zz,xx,yy};
            c[cnt+6]={zz,yy,xx};
            cnt+=6;
        }


        sort(c+1,c+1+cnt,cmp);
        for(int i=1;i<=cnt;i++)f[i]=c[i].z;
        for(int i=1;i<=cnt;i++){
            for(int j=1;j<i;j++){
                if(c[i].x<c[j].x&&c[i].y<c[j].y){
                    f[i]=max(f[i],f[j]+c[i].z);
                }
            }
            ans=max(ans,f[i]);
        }
        printf("Case %d: maximum height = %lld\\n",Case,ans);
    }
    return 0;
}

D - Doing Homework

「题意」
有 n 个作业,完成某个作业需要一定的时间,而且每个作业有一个截止时间,若超过截止时间,一天就要扣一分。如何安排做作业,使得扣的分数最少。
Tips: 如果开始做某个作业,就必须把这个作业做完了,才能做下一个作业。

数据范围15,状态压缩DP
「代码」

/*参考https://blog.csdn.net/qq_46276931/article/details/116567454*/
#include<bits/stdc++.h>
using namespace std;
const int N=16;
int f[1<<N],v[1<<N],last[1<<N];
char name[N][105];
int d[N],c[N];

void print(int x){
    if(!x)return;
    print(x-(1<<last[x]));
    cout<<name[last[x]]<<endl;
}
int main(){
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        for(int i=0;i<n;i++)cin>>name[i]>>d[i]>>c[i];

        int siz=1<<n;
        for(int i=1;i<=siz-1;i++){
            f[i]=1e9+7;
            for(int j=n-1;j>=0;j--){
                int k = 1 << j;
				if (!(i & k)) continue;
				int w = v[i - k] + c[j] - d[j];//算转移过来超出的时间
				if (w < 0) w = 0;//截止前完成了
				if (f[i] > f[i - k] + w) {
					f[i] = f[i - k] + w;//更新最小值
					v[i] = v[i - k] + c[j];//记录第几天了
					last[i] = j;//记录前一个状态
				}
            }
        }

        cout<<f[siz-1]<<endl;
        print(siz-1);
    }
    return 0;
}

E - Super Jumping! Jumping! Jumping!

「题意」
求最大上升子序列和
「代码」

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

typedef long long LL;
const int N=1e3+10;
LL f[N],a[N];

int main(){
    int n;
    while(~scanf("%d",&n)&n){
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            f[i]=a[i];
        }
        LL ans=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<i;j++){
                if(a[j]<a[i])f[i]=max(f[i],f[j]+a[i]);
            }
        }
        for(int i=1;i<=n;i++)ans=max(ans,f[i]);
        printf("%lld\\n",ans);
    }
    return 0;
}

F - Piggy-Bank

「题意」
完全背包,求体积恰好为m的物品组合的最小价值
「代码」

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

typedef long long LL;
const int N=510,M=10005;
int w[N],v[N];
int f[N][M];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int E,F,n,m;scanf("%d%d%d",&E,&F,&n);
        for(int i=1;i<=n;i++)scanf("%d%d",&v[i],&w[i]);
        m=F-E;
        memset(f,0x3f,sizeof f);
        for(int i=0;i<=n;i++)f[i][0]=0;//从0开始
        
        for(int i=1;i<=n;i++){
            for(int j=0;j<=m;j++){
                f[i][j]=f[i-1][j];
                if(j>=w[i])f[i][j]=min(f[i][j],f[i][j-w[i]]+v[i]);
            }
        }
        
        if(f[n][m]!=0x3f3f3f3f)printf("The minimum amount of money in the piggy-bank is %lld.\\n",f[n][m]);
        else puts("This is impossible.");
    }
}

G - 免费馅饼

「题意」
馅饼从天掉,降落范围[0,10]。小王开始站在位置5,每次最大水平移动距离为1。问在最多能接到多少硬币,背包容量不限,同一位置同一时间可能有多个馅饼。
走地图DP
「代码」

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

typedef long long LL;
const int N=1e5+10;
LL g[N][11],f[N][11];
int Tmax;
LL dfs(int t,int pos){
    LL tmp=0;
    if(t>Tmax)return 0;
    if(f[t][pos])return f[t][pos];
    tmp=max(tmp,dfs(t+1,pos));
    if(pos-1>=0)tmp=max(tmp,dfs(t+1,pos-1));
    if(pos+1<=10)tmp=max(tmp,dfs(t+1,pos+1));
    return f[t][pos]=tmp+g[t][pos];
}
int main(){
    int n;
    while(~scanf("%d",&n)&&n){
        memset(g,0,sizeof g);
        memset(f,0,sizeof f);
        Tmax=0;
        for(int i=1;i<=n;i++){
            int x,T;scanf("%d%d",&x,&T);
            g[T][x]++;
            Tmax=max(Tmax,T);
        }

        LL ans=dfs(0,5);
        printf("%lld\\n",ans);
    }
    return 0;
}

H - Tickets

「题意」
现在有n个人要买电影票,如果知道每个人单独买票花费的时间,还有和前一个人一起买花费的时间,问最少花多长时间可以全部买完票。
状态机DP
「代码」

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

typedef long long LL;
const int N=2e3+10;

int single_time[N],merge_time[N],value[N];
int f[N][2];

int main(){
    int n;
    while(~scanf("%d",&n)){
        while(n--){
            memset(f,0,sizeof f);
            int k;scanf("%d",&k);
            int all_time=0;
            for(int i=1;i<=k「kuangbin带你飞」专题十二 基础DP

kuangbin专题十二 基础DP1从入门到熟练9+1题

算法系列学习状压dp [kuangbin带你飞]专题十二 基础DP1 D - Doing Homework

算法系列学习[kuangbin带你飞]专题十二 基础DP1 G - 免费馅饼

算法系列学习DP和滚动数组 [kuangbin带你飞]专题十二 基础DP1 A - Max Sum Plus Plus

[kuangbin] 专题13 基础计算几何 题解 + 总结