一些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\n", 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\n", 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

 

posted @ 2020-10-06 21:27  LightAc  阅读(214)  评论(0编辑  收藏  举报
返回顶端