• 一些DP题(顺便找的)


    注:一日恰饭之余,LL大佬说刷啥线段树不如做些DP题,想想也是==然后刷了几道DP题

    https://vjudge.net/contest/399437#overview

    后续写了上面contest的题,在这篇随笔继续更新

    两道下饭题

     思路:数字三角形,最简单的DP,没有之一

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll dp[210][210];
    ll a[210][210];
    int main (){
    	int T;
    	scanf("%d", &T);
    	int num = 1;
    	while(T--) {
    		int N;
    		scanf("%d", &N);
    		memset(dp, 0, sizeof dp);
    		memset(a, 0,sizeof a);
    		for(int i = 1; i <= 2 * N - 1; ++i) {
    			if(i <= N){
    				for(int j = 1; j <= i; ++j) {
    					scanf("%lld", &a[i][j]);
    				}	
    			}
    			else {
    				for(int j = 1; j <= 2 * N - i; ++j) {
    					scanf("%lld", &a[i][j]);
    				}	
    			}
    
    		}
    		dp[1][1] = a[1][1];
    		for(int i = 2; i <= 2 * N - 1; ++i) {
    			if(i <= N){
    				for(int j = 1; j <= i; ++j) {
    					dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1]) + a[i][j];
    				}	
    			}
    			else {
    				for(int j = 1; j <= 2 * N - i; ++j) {
    					dp[i][j] = max(dp[i - 1][j], dp[i - 1][j + 1]) + a[i][j];
    				}	
    			}
    		}
    //		for(int i = 1; i <= 2 * N - 1; ++i) {
    //			if(i <= N){
    //				for(int j = 1; j <= i; ++j) {
    //					printf("%lld ", dp[i][j]);
    //				}	
    //			}
    //			else {
    //				for(int j = 1; j <= 2 * N - i; ++j) {
    //					printf("%lld ", dp[i][j]);
    //				}	
    //			}
    //			putchar(10);
    //		}
    		printf("Case %d: %lld
    ", num++, dp[2 * N - 1][1]);
    	}
    }
    /*
    2
    4
    7
    6 4
    2 5 10
    9 8 12 2
    2 12 7
    8 2
    10
    2
    1
    2 3
    1
    */ 
    

     

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll dp[25][10];
    ll a[25][10];
    int main () {
    	int n;
    	scanf("%d", &n);
    	int num = 1;
    	while(n--) {
    		getchar();
    		int t;
    		scanf("%d", &t);
    		for(int i = 1; i <= t; ++i) {
    			for(int j = 1; j <= 3; ++j) {
    				scanf("%lld", &a[i][j]);
    				if(i == 1) {
    					dp[i][j] = a[i][j];
    				}
    			}
    		}
    		for(int i = 2; i <= t; ++i) {
    			for(int j = 1; j <= 3; ++j) {
    				ll minn = 0x3f3f3f3f;
    				for(int k = 1; k <= 3; ++k) {
    					if(j != k)
    						minn = min(dp[i - 1][k], minn);
    				}
    				dp[i][j] = minn + a[i][j];
    			}
    		}
    		ll ans = 0x3f3f3f3f;
    		for(int i = 1; i <= 3; i++) {
    			ans = min(ans, dp[t][i]);
    		}
    		printf("Case %d: %lld
    ", num++, ans);
    	} 
    } 
    /*
    2
    
    4
    13 23 12
    77 36 64
    44 89 76
    31 78 45  
     
    3
    26 40 83
    49 60 57
    13 89 99
    */
    

    思路:与上题一样

    今日做了这两道题发现这个contest属实easy

    然后上网搜了波

    难点儿的题集

    被虐自闭

    地址

    先使用前缀和预处理,然后可以知道状态转移方程dp[i][j] = max(dp[i -1][j], dp[i - m][j - 1] + sum[i] - sum[i - m]);前者代表不选它,后者代表选它情况的和

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll dp[5010][5010];
    ll sum[5010];
    int main () {
    	ios::sync_with_stdio(false);
    	cin.tie(0);
    	ll n, m, k;
    	cin >> n >> m >> k;
    	memset(sum, 0, sizeof sum);
    	memset(dp, 0, sizeof dp);
    	for(int i = 1; i <= n; ++i) {
    		ll temp;
    		cin >> temp;
    		sum[i] = sum[i - 1] + temp;
    	} 
    	//代表前i个元素,选j组的情况的和 
    	for(int i = 1; i <= n; ++i) {
    		for(int j = 1; j <= k; ++j) {
    			if(i - m >= 0)
    				dp[i][j] = max(dp[i -1][j], dp[i - m][j - 1] + sum[i] - sum[i - m]);
    		}
    	}
    	cout << dp[n][k] << endl;
    } 
    

    来道硬核题

     数论与DP的集合,重点关注右边开区间的个数,如果查一个是可以通过自身自加来满足,如果刚好合适的话就只用关注i - 1(dp[i][j] = (dp[i][j] + dp[i - 1][j]) % MODE;)反之(dp[i][j] = (dp[i][j] + dp[i - 1][j - 1]) % MODE;)下面同理

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll MODE = 1e9 + 7;
    ll dp[2020][2020];//dp[i][j]代表前i个元素中, 右边有j个开区间的情况 
    int main () {
    	ios::sync_with_stdio(false);
    	cin.tie(0);
    	ll n, h;
    	cin >> n >> h;
    	vector<ll> a(n + 1);
    	for(int i = 1; i <= n; ++i) {
    		cin >>a[i];
    	}
    	memset(dp, 0, sizeof dp);
    	dp[1][0] = (a[1] == h || a[1] + 1 == h) ? 1 : 0;
    	dp[1][1] = a[1] + 1 == h ? 1 : 0;
    	for(ll i = 2; i <= n; ++i) {
    		for(ll j = max(h - a[i] - 1, 0ll); j <= min(i, h - a[i]); ++j){
    //			cout<<i<<' '<<j<<' '<<a[i]<<endl;
    			if(a[i] + j == h) {
    				dp[i][j] = (dp[i][j] + dp[i - 1][j]) % MODE;
    				if(j != 0)  {
    					dp[i][j] = (dp[i][j] + dp[i - 1][j - 1]) % MODE;	
    				}
    			}
    			if(a[i] + j + 1 == h) {
    				dp[i][j] = (dp[i][j] + dp[i - 1][j] * (j + 1)) % MODE;
    				dp[i][j] = (dp[i][j] + dp[i - 1][j + 1] * (j + 1)) % MODE;
    			}
    		}
    	}
    	cout << dp[n][0] << endl;
    } 
    

     此题属实烧脑,目测银牌题水平

     更新于 2020-10-06 21:25:26

  • 相关阅读:
    【转载】Scarbee Pre-Bass 贝司的使用教程
    罗兰管弦乐音色表【中英文对照】 ----转载
    快速查询
    免费好用的Noto字体
    用了一年多之后才搞懂阿里云OSS收费细则
    “生成能够被扫描枪正常扫描出中文的二维码”
    .NET Core 3.0正式版发布
    快速删除一个“大目录”
    WSL2(预览版)体验笔记
    局域网地址为什么是192.168.X.X?为什么连上公司的VPN就上不了网?
  • 原文地址:https://www.cnblogs.com/lightac/p/13775576.html
Copyright © 2020-2023  润新知