kaungbin 专题12-基础dp选做

1.max plus plus

思路:设dp[i][j]为以j结尾分为i分的最大值
状态转移方程:dp[i][j]=max(dp[i][j-1],max(dp[i-1][k])(k<=j-1)+a[j]
1.由于数据过大,进行滚动数组优化
2.max(dp[i-1][k])==dp[i-2][j-1]==pre,可对上次结果保存处理
#include <iostream>
#include<map>
#include<algorithm>
#include<string.h>
#define ll long long
#define pq priority_queue
#define repr(i, x, y) for (int i = x; i <= y; i++)
#define rep(i, x, y) for (int i = x; i < y; i++)
#define drep(i, x, y) for (int i = x; i >= y; i--)
#define pb push_back
#define P make_pair
#define pii pair<int, int>
#define mem(x, y) memset(x, y, sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f, maxn = 2e5 + 5;
const double eps = 1e-8;
int a[1000005],dp[1000005],l[1000005];
int main(){
	//freopen("D://devc++homework//vs2//.vscode//in.txt","r",stdin);
	//freopen("D://devc++homework//vs2//.vscode//myout.txt","w",stdout);
	int n,m;
	while(~scanf("%d%d",&m,&n)){
		mem(dp,0),mem(l,0);
		repr(i,1,n) scanf("%d",&a[i]);
		int maxx;
		repr(i,1,m){
			maxx=-(1<<30);
			repr(j,i,n){
				dp[j]=max(dp[j-1],l[j-1])+a[j];//状态转移
				l[j-1]=maxx;//保存
				maxx=max(maxx,dp[j]);
			}
		}
		printf("%d\n",maxx);
	}
	//cout<<endl<<clock();
	return 0;
}

2. super jumping

思路:线性dp
状态转移方程:dp[i]=max(dp[j])+a[i](j<i&&a[i]>a[j])
#include <iostream>
#include <string.h>
#include <algorithm>
#define ll long long
#define pq priority_queue
#define repr(i, x, y) for (int i = x; i <= y; i++)
#define rep(i, x, y) for (int i = x; i < y; i++)
#define drep(i, x, y) for (int i = x; i >= y; i--)
#define pb push_back
#define P make_pair
#define pii pair<int, int>
#define mem(x, y) memset(x, y, sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f, maxn = 2e5 + 5;
const double eps = 1e-8;
int dp[maxn],a[maxn];
int main() {
    int n;
    while(cin>>n&&n){
        mem(dp,0);
        repr(i,1,n) cin>>a[i],dp[i]=a[i];
        int ans=0;
        repr(i,1,n){
            repr(j,i+1,n){
                if(a[j]>a[i]) dp[j]=max(dp[j],dp[i]+a[j]);
            }
            ans=max(ans,dp[i]);
        }
        cout<<ans<<'\n';
    }
    return 0;
}

3.最少拦截系统

思路:贪心加二分
为使当前序列更有潜力进行上升,在线操作二分,每次进行替换。
1.dp初始化为inf
2.本方法只能求得长度
#include <iostream>
#include<map>
#include<algorithm>
#include<string.h>
#define ll long long
#define pq priority_queue
#define repr(i, x, y) for (int i = x; i <= y; i++)
#define rep(i, x, y) for (int i = x; i < y; i++)
#define drep(i, x, y) for (int i = x; i >= y; i--)
#define pb push_back
#define P make_pair
#define pii pair<int, int>
#define mem(x, y) memset(x, y, sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f, maxn = 2e5 + 5;
const double eps = 1e-8;
int a[maxn],dp[maxn];
int main(){
	//freopen("D://devc++homework//vs2//.vscode//in.txt","r",stdin);
	//freopen("D://devc++homework//vs2//.vscode//myout.txt","w",stdout);
	int n;
	while(cin>>n){
		mem(dp,inf);
		repr(i,1,n) cin>>a[i],*lower_bound(dp+1,dp+n+1,a[i])=a[i];
		printf("%d\n",lower_bound(dp+1,dp+n+1,inf)-dp-1);
	}
	//cout<<endl<<clock();
	return 0;
}

4. common subsequence

思路:设dp[i][j]为a长i,b长j时最长公共子序列
状态转移方程:a[i]==b[j]: dp[i+1][j+1]=dp[i][j]+1
				  else:  dp[i+1][j+1]=max(dp[i][j+1]),dp[i+1][j])
#include<iostream>
#include<algorithm>
#include<string.h>
#include<cstring>
#define ll long long
#define pq priority_queue
#define repr(i,x,y) for(int i=x;i<=y;i++)
#define rep(i,x,y) for(int i=x;i<y;i++)
#define drep(i,x,y) for(int i=x;i>=y;i--)
#define pb push_back
#define P make_pair
#define pii pair<int,int>
#define mem(x,y) memset(x,y,sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f, maxn = 2e5 + 5;
const double eps = 1e-8;
string a,b;
int dp[1005][1005];
int main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin>>a>>b){
        mem(dp,0);
        rep(i,0,a.size()){
            repr(j,0,b.size()){
                if(a[i]==b[j]){
                    dp[i+1][j+1]=dp[i][j]+1;
                }
                else{
                    dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]);
                }
            }
        }
        cout<<dp[a.size()][b.size()]<<'\n';
        //cout<<endl<<clock();
    }
    return 0;
}

5.Phalanx

思路:最大对称子矩阵,设dp[i][j]为(i,j)点向上向右扩张最大子矩阵
1.初始化dp为1,每次遍历出无法扩张的结尾
2.状态转移方程:dp[i][j]=min(dp[i-1][j+1],i-ii+1)+1(ii为遍历结尾)
#include<iostream>
#include<algorithm>
#include<string.h>
#define ll long long
#define pq priority_queue
#define repr(i,x,y) for(int i=x;i<=y;i++)
#define rep(i,x,y) for(int i=x;i<y;i++)
#define drep(i,x,y) for(int i=x;i>=y;i--)
#define pb push_back
#define P make_pair
#define pii pair<int,int>
#define mem(x,y) memset(x,y,sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f, maxn = 2e5 + 5;
const double eps = 1e-8;
int n;
int dp[2005][2005];
char a[2005][2005];
int main() {
    while(~scanf("%d",&n)&&n){
        repr(i,1,n){
            repr(j,1,n){
                cin>>a[i][j];
            }
        }
        mem(dp,0);
        int ans=1;
        repr(i,1,n){
            repr(j,1,n){
                dp[i][j]=1;
                int ii=i-1,jj=j+1;
                while(a[i][jj]==a[ii][j]&&ii&&jj<=n){
                    ii--,jj++;
                }
                dp[i][j]=min(dp[i-1][j+1],i-ii-1)+1;
                ans=max(ans,dp[i][j]);
            }
        }
        cout<<ans<<'\n';
    }
    //cout<<endl<<clock();
    return 0;
}

6.免费馅饼

思路:设dp[i][j]为i时刻j位置可获得最大馅饼数
1.因无法得到后时刻最大获得数,故倒序dp
2.状态转移方程dp[i][j]=max(dp[i+1][j],dp[i+!][j-1],dp[i+1][j+1])(防止位置负数,对其加1操作)
#include<iostream>
#include<algorithm>
#include<string.h>
#define ll long long
#define pq priority_queue
#define repr(i,x,y) for(int i=x;i<=y;i++)
#define rep(i,x,y) for(int i=x;i<y;i++)
#define drep(i,x,y) for(int i=x;i>=y;i--)
#define pb push_back
#define P make_pair
#define pii pair<int,int>
#define mem(x,y) memset(x,y,sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f, maxn = 2e5 + 5;
const double eps = 1e-8;
int n;
int dp[maxn][15];
int a[maxn][15];
int main() {
    while(~scanf("%d",&n)&&n){
        int maxx=-1;
        mem(dp,0),mem(a,0);
        int x,y;
        repr(i,1,n){
            scanf("%d%d",&x,&y);
            a[y][++x]++;
            maxx=max(maxx,y);
        }
        drep(i,maxx,0){
            repr(j,1,11){
                dp[i][j]=max(dp[i+1][j+1],max(dp[i+1][j],dp[i+1][j-1]))+a[i][j];
            }
        }
        printf("%d\n",dp[0][6]);
    }
    //cout<<endl<<clock();
    return 0;
}

7.Tickets

思路:简单dp,注意格式
1.状态转移方程:dp[i]=min(dp[i-1]+a[i],dp[i-2]+b[i])
//mode by lsy
#include<iostream>
#include<algorithm>
#include<string.h>
#define ll long long
#define pq priority_queue
#define repr(i,x,y) for(int i=x;i<=y;i++)
#define rep(i,x,y) for(int i=x;i<y;i++)
#define drep(i,x,y) for(int i=x;i>=y;i--)
#define pb push_back
#define P make_pair
#define pii pair<int,int>
#define mem(x,y) memset(x,y,sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f, maxn = 2e5 + 5;
const double eps = 1e-8;
int dp[maxn],a[maxn],b[maxn];
int n,k;
int main() {
    cin>>n;
    while(n--){
        cin>>k;
        repr(i,1,k) cin>>a[i];
        repr(i,2,k) cin>>b[i];
        dp[1]=a[1];
        repr(i,2,k){
            dp[i]=min(dp[i-1]+a[i],dp[i-2]+b[i]);
        }
        int h=8,min=0,sec=0;
        sec+=dp[k];
        min+=sec/60%60;
        h+=sec/3600;
        sec%=60;
        printf("%02d:%02d:%02d ",h,min,sec);
        if(h>=12) puts("pm");
        else puts("am");
    }
    //cout<<endl<<clock();
    return 0;
}
/*
    Simplicity is a prerequisite for stability.
            ——by acmer lsy
*/

8.FatMouse and Cheese

思路:记忆化搜索
1.设dp[x][y]为x,y点获得最大值
2.若以更新过则直接返回
3.dp[i][j]=max(dp上下左右)(if满足条件)
#include<iostream>
#include<algorithm>
#include<string.h>
#define ll long long
#define pq priority_queue
#define repr(i,x,y) for(int i=x;i<=y;i++)
#define rep(i,x,y) for(int i=x;i<y;i++)
#define drep(i,x,y) for(int i=x;i>=y;i--)
#define pb push_back
#define P make_pair
#define pii pair<int,int>
#define mem(x,y) memset(x,y,sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f, maxn = 2e5 + 5;
const double eps = 1e-8;
int n,m;
int dp[2005][2005];
int a[2005][2005];
int d[4][2]={1,0,-1,0,0,1,0,-1};
int dfs(int x,int y){
    if(dp[x][y]) return dp[x][y];
    int ans=0;
    repr(i,1,m){
        rep(j,0,4){
            int xx=x+d[j][0]*i,yy=y+d[j][1]*i;
            if(a[x][y]<a[xx][yy]&&xx>0&&yy>0&&xx<=n&&yy<=n){
                ans=max(dfs(xx,yy),ans);
            }
        }
    }
    return dp[x][y]=a[x][y]+ans;
}
int main() {
    while(~scanf("%d%d",&n,&m)&&n!=-1&&m!=-1){
        repr(i,1,n){
            repr(j,1,n){
                cin>>a[i][j];
            }
        }
        mem(dp,0);
        cout<<dfs(1,1)<<'\n';
    }
    //cout<<endl<<clock();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值