动态规划专题:线性dp、背包问题,区间

news2024/11/18 23:42:54

目录

方块与收纳盒

舔狗舔到最后一无所有

可爱の星空

数字三角形

花店橱窗

[NOI1998]免费馅饼

[NOIP2002]过河卒

[NOIP2008]传球游戏

「木」迷雾森林

[NOIP2004]合唱队形

[NOIP1999]拦截导弹

数学考试

小A买彩票

购物

牛牛的旅游纪念品

[NOIP2001]装箱问题

[NOIP2005]采药

[NOIP2006]开心的金明

CSL分苹果

失衡天平

[NOIP2006]金明的预算方案

队伍配置

取数游戏2

石子合并

石子合并

[NOIP2008]传纸条

[NOIP2000]方格取数

[NOIP2010]乌龟棋

[NOIP2006]能量项链

[NOIP2018]货币系统

方块与收纳盒

预处理之后很简单,已知0,1,2的方案数,那么之后每次都是i-1的方案数+i-2的方案数。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
const int N=100;
int dp[N];
void solve() {
	int n;
	cin>>n;
	cout<<dp[n]<<endl;
}
signed main() {
	ios::sync_with_stdio ( false );cin.tie ( nullptr );	cout.tie ( nullptr );
	int oyyo = 1;
	dp[0]=1;
	dp[1]=1;
	dp[2]=2;
	for(int i=3;i<=100;i++){
		dp[i]=dp[i-1]+dp[i-2];
	}
	cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

舔狗舔到最后一无所有

因为不能连续三天吃一样的东西,所以可以先假设第一天吃A,然后情况就是第i-1天吃A,第i-1天吃B,第i-1天吃C,其中第i-1天吃A时,第i-2天不能吃A,只能吃B和C。

所以第i天吃A的情况就是第i-2天吃B,第i-2天吃C,第i-1天吃B,第i-1天吃C。

对于第i天吃B,C的情况和吃A的情况一样。

B:第i-2天吃A,第i-2天吃C,第i-1天吃A,第i-1天吃C。

C:第i-2天吃A,第i-2天吃B,第i-1天吃A,第i-1天吃B。

所以最后第i天的情况总和为2*dp[i-1]+2*dp[i-2]

#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
const int N=100005;
const int mod=1e9+7;
int dp[N];
void solve() {
	int n;
	cin>>n;
	cout<<dp[n]<<endl;
	
}
signed main() {
	ios::sync_with_stdio ( false );cin.tie ( nullptr );cout.tie ( nullptr );
	int oyyo = 1;
	dp[0]=1;
	dp[1]=3;
	dp[2]=9;
	for(int i=3;i<N;i++){
		dp[i]=dp[i-1]%mod*2%mod+dp[i-2]*2%mod;
		dp[i]%=mod;
	}
	cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

可爱の星空

给了你n个点,可以连成图,u和v两个小图连图的代价是  |u连通块的大小-v连通块的大小|  (绝对值),问你最终连成一个大块的最小代价是什么。

挺牛逼的题,被吓了。

他的范围会有一些很大的,所以一时间不知道怎么搞。问题的解法是单一的,对于一个数,最小代价的解法就是尽量平分成两个相同大小,奇数就是 n/2 和 n/2+1,偶数就是两个 n/2,当n==1,n==2时,都直接返回0,状态方程很好写,但当面对大数就很难堪,其实只要稍微有一些改写就好了。

如果你让这里再去递归两次就会超时,所以直接乘2就好。这个每次都除二,大胆写就好。我就是没胆量。

#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
const int N=100005;
const int mod=1e9+7;
int answ(int n){
	if(n==1)
		return 0;
	if(n==2){
		return 0;
	}
	if(n%2==1){
		return answ(n/2)+answ(n/2+1)+1;
	}else{	
		return answ(n/2)*2;//**there。**//
	}
}
void solve() {
	int n;
	cin>>n;
	cout<<answ(n)<<endl;
}
signed main() {
	ios::sync_with_stdio ( false );cin.tie ( nullptr );cout.tie ( nullptr );
	int oyyo = 1;
	
	cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

数字三角形

照他说的做。

第一个数的公式是k=i*(i+1)/2-(i-1)

#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
const int N=100005;
const int mod=1e9+7;

void solve() {
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		int k;
		k=i*(i+1)/2-(i-1);
		
		for(int j=1;j<=i;j++){
			printf("%4d",k+j-1);
		}
		cout<<endl;
	}
}
signed main() {
	//ios::sync_with_stdio ( false );cin.tie ( nullptr );cout.tie ( nullptr );
	int oyyo = 1;
	
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

花店橱窗

这个❀首先要满足题目的要求,每个花都要按原编号顺序从左到右排列。所以第一个花最多摆到末尾位置-f+1,第 i  个花最前摆到 i 位置。

我们可以这样做。对于第 x,y 位置,它可以继承 x-1行,(x~y-1)的所有情况,所以我们的dp数组就去记录在每个位置下,他最多的美观度是多少。首先对第一行,如果当前的花 A 加上花瓶构成的美观度,小于这一行目前出现的最大值,那么我们就直接记录最大值就好,因为对于下一行(下一个要判断的花),我们如果会再考虑现在这个花 A ,当且仅当在下一行我们会走到A花之后的位置,这样才会去讨论 A 的价值,但在这个情况下,我们完全可以选择A花之前的最优情况,所以直接去记录目前为止的最大值就好。对于之后的行也是如此,如果当前花A(x,y)的价值+dp[x-1][y-1]的价值(因为dp[x-1][y-1] 就是在这个位置可以选到的最大价值了)小于这一行的上一个位置dp[x][y-1],那么就去继承他左边的位置。否则就是他自己又产生了新的最大值。

坐标的输出比较搞,我搜的。但不难。

#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
const int N=105;
const int mod=1e9+7;

int a[N][N];
int dp[N][N];
int d[N];
void solve() {
	
	int f,v;//一共有F中❀,V个花瓶。
	cin>>f>>v;
	
	for(int i=1;i<=f;i++){
		for(int j=1;j<=v;j++){
			cin>>a[i][j];
			dp[i][j]=-inf;//初始化dp数组,以为会存在负数,为了让dp[i]记录当前可能的最大情况就要初始化为负无穷。
		}
	}
	
	int maxn=a[1][1];
	for(int i=1;i<=v-f+1;i++){
		if(a[1][i]>maxn){
			dp[1][i]=a[1][i];
			maxn=a[1][i];
			//首先先去找第一行的最大可能情况。如果他不够大,他可以继承前面的最大情况。
		}else{
			dp[1][i]=maxn;
		}
	}
	
	for(int i=2;i<=f;i++){
		for(int j=i;j<=v-f+i;j++){//每一行只能从第i个开始选,因为要满足题目所给“左右一致”
			//之后哦每一行,他要么是继承前一个的最大值。
			dp[i][j]=max(dp[i][j-1],dp[i-1][j-1]+a[i][j]);
		}
	}
	//找到后输出最大值。
	cout<<dp[f][v]<<endl;
	//然后回溯去寻找序列。
	int ans=dp[f][v];
	int cnt=f;
	for(int i=f;i>=1;i--){
		for(int j=1;j<=v;j++){
			if(dp[i][j]==ans){
				d[cnt--]=j;//当他找到和要要寻找的数等大的。就直接传递回上一层,这样字典序最小。
				ans-=a[i][j];//找到后减去这一行的最大值位置。就是上一行所能产生的最大值了。
				break;
			}
		}
	}//出
	for(int i=1;i<=f;i++){
		cout<<d[i]<<" ";
	}
}
signed main() {
	ios::sync_with_stdio ( false );cin.tie ( nullptr );cout.tie ( nullptr );
	int oyyo = 1;
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

[NOI1998]免费馅饼

[NOIP2002]过河卒

因为只能向下或向右去走,所以到一个点只有通过它左边的路或上边的路。

那么到某点的路径条数=到它左边点的条数+到它上面点的条数(前提是这两点都可到)

真正到边线上的点的路径条数应该是他的上一个点的条数(上边界就是它左边的点,左边姐就是它上边的点)而不是简单的规定为1。还有特殊的就是原点了。我们把它规定路径条数为1。

用数组记录马控制的区域表示此路不通。在循环判断到这个点后直接跳过就好。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>

void solve(){
	int n,m,p,q;
	int a[30][30]={0};
	int map[30][30]={0};
	cin>>n>>m>>p>>q;
	map[p][q]=1;
	map[p-2][q-1]=1;
	map[p-2][q+1]=1;
	map[p+2][q+1]=1;
	map[p+2][q-1]=1;
	map[p-1][q-2]=1;
	map[p-1][q+2]=1;
	map[p+1][q+2]=1;
	map[p+1][q-2]=1;
	
	for(int i=0;i<=n;i++){
		for(int j=0;j<=m;j++){
			if(map[i][j]){
				continue;
			}else{
				if(i==0 and j==0){
					a[i][j]=1;
				}else if(i==0 and j>0){
					a[i][j]=a[i][j-1];
				}else if(j==0 and i>0){
					a[i][j]=a[i-1][j];
				}else{
					a[i][j]=a[i-1][j]+a[i][j-1];
				}
			}
		}
	}
	cout<<a[n][m]<<endl;
	
}
signed main() {
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int t=1;
	//cin>>t;
	while(t--) {
		solve();
	}
	return 0;
}

[NOIP2008]传球游戏

每个同学可以从左或右边同学接球,即当前这一轮中间同学可以拿到球的总方法=上一轮左同学的可拿球方法+上一轮右同学的可拿球方法。

状态转移方程 dp[i][j] = dp[i-1][j-1]+dp[i-1][j+1];

题目说一开始从小蛮开始,那么一开始小蛮就得到了一个球,只有这一个方法可以得到球。

记住边界要特殊判断。就好。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
const int N=35;
int dp[N][N];
void solve(){
	int n,m;//N个人,传了M次后
	cin>>n>>m;
	dp[0][1]=1;
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			if(j==1){
				dp[i][j]=dp[i-1][n]+dp[i-1][2];
			}else if(j==n){
				dp[i][j]=dp[i-1][j-1]+dp[i-1][1];
			}else{
				dp[i][j]=dp[i-1][j-1]+dp[i-1][j+1];
			}
		}
	}
	cout<<dp[m][1]<<endl;
}
signed main() {
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int t=1;
	//cin>>t;
	while(t--) {
		solve();
	}
	return 0;
}

「木」迷雾森林

刚开始在左下方,要求只能向上或向右走,走到右上方,有1的地方不能走,求方案数对2333取模。

我们把问题分解成加法问题,开一个数组s,s【i,j】表示从左下走到i,j这个点的方案数是多少,当前的点i,j是由下方【i+1,j】和左边【i,j-1】的方案数相加,而【n,1】的方案数是1,我们遇到1的时候直接令这个点方案数为0就可以了,从下往上dp,最后输出s【1,n】%2333即可。

dp [ i] [ j ] = dp [ i - 1 ] [ j ] + d p [ i ] [ j - 1 ]

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

#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
const int N=5005;
const int mod=1e9+7;

int a[3005][3005];
int s[3005][3005];

template<class T>inline void read(T &res)
{
	char c;T flag=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

void solve() {
	int n,m;
	memset(s,0,sizeof s);
	read(n),read(m);
	s[n][1]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			read(a[i][j]);
		}
	}
	for(int i=n;i>=1;i--){
		for(int j=1;j<=m;j++){
			if(i==n and j==1){
				continue;
			}
			if(a[i][j]==1){
				s[i][j]=0;
				continue;
			}
			s[i][j]=s[i+1][j]%2333+s[i][j-1]%2333;
			s[i][j]%=2333;
		}
	}

	cout<<s[1][m]<<endl;
}
signed main() {
	ios::sync_with_stdio ( false );cin.tie ( nullptr );cout.tie ( nullptr );
	int oyyo = 1;
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

[NOIP2004]合唱队形

本题是要求出从 第一个人到第i个最高的人的最长上升子序列  以及从第i个人到第n个人的最长下降子序列(其实就是第n个人反向到第i个人的最长上升子序列)

建立二维数组dp[105][2]。

dp[i][0]代表以第i个人为结尾的最长上升子序列长度。(整个合唱队形没有下降)

dp[i][1]代表以第i个人为结尾的最长合唱队形,但至少有一个人的身高呈下降趋势(合唱队形有下降)

显然,max(a[i][0],a[i][1])代表前i个人的最长合唱队形。

#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
const int N=100005;
const int mod=1e9+7;
int dp[105][2];
void solve() {
	int n;
	cin>>n;
	vector<int>a(n+1);
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		dp[i][0]=1;
		for(int j=1;j<i;j++){
			if(a[i]>a[j]){
				dp[i][0]=max(dp[i][0],dp[j][0]+1);
			}
		}
	}
	for(int i=1;i<=n;i++){
		dp[i][1]=1;
		for(int j=1;j<i;j++){
			if(a[i]<a[j]){
				dp[i][1]=max(dp[i][1],max(dp[j][0],dp[j][1])+1);
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		ans=max(ans,max(dp[i][0],dp[i][1]));
	}
	cout<<n-ans<<endl;
}
signed main() {
	ios::sync_with_stdio ( false );cin.tie ( nullptr );cout.tie ( nullptr );
	int oyyo = 1;
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

[NOIP1999]拦截导弹

真的没搞懂。。。。。。

#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
const int N=100005;
const int mod=1e9+7;

int f[N];
int a[N];
int n,t;
void solve() {

	while(cin>>a[++n]);
	n--;
	t=0;
	memset(f,0,sizeof(f));f[0]=inf;
	for(int i=1;i<=n;i++){
		int l=0,r=t+1;
		while(r-l>1){
			int m=l+(r-l)/2;
			if(f[m]>=a[i]){
				l=m;
			}else{
				r=m;
			}
		}
		int x=l+1;
		if(x>t){
			t=x;
		}
		f[x]=a[i];
	}
	cout<<t<<endl;
	t=0,memset(f,0,sizeof(f));
	f[0]=0;
	for(int i=1;i<=n;i++){
		int l=0,r=t+1;
		while(r-l>1){
			int m=l+(r-l)/2;
			if(f[m]<a[i]){
				l=m;
			}else{
				r=m;
			}
		}
		int x=l+1;
		if(x>t){
			t=x;
		}
		f[x]=a[i];
	}
	cout<<t<<endl;
	
}
signed main() {
	ios::sync_with_stdio ( false );cin.tie ( nullptr );cout.tie ( nullptr );
	int oyyo = 1;
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

数学考试

先求前缀和,因为两个区间不相交,所以找一个基准点,找到该基准点左侧的sum最大的的区间(可以将该基准点视为在左区间),再在基准点右侧找到sum最大的区间,最后相加。

让每个数都做基准点,找到它们各自的左区间sum最大
  1. zuo[i] 为以 i 做基准点,左侧的sum最大区间。
  2. 因为要求的的区间长度为k,所以 i 要从 k开始,如果从 k 以前的数开始的话,区间长度根本都不满足题中要求的长度k。
让每个数都做基准点,找到它们各自的右区间sum最大
  1. you[i] 为以 i 做基准点,右侧的sum最大区间。
  2. i要从从右数k个数开始,即n - k + 1
#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf 0x3f3f3f3f3f3f3f3f3f
#define pii pair<int,int>
const int mod=1e9+7;
const int N=200005;
int b[N];
int you[N];
int a[N];

void solve() {
	int n,k;
	cin>>n>>k;
	memset(a,0,sizeof(a));
	memset(you,-1e4,sizeof(you));
	memset(b,0,sizeof(b));

	for(int i=1;i<=n;i++){
		cin>>a[i];
	}

	for(int i=1;i<=n;i++){
		b[i]=b[i-1]+a[i];
	}

	for(int i=n-k+1;i>=1;i--){
		you[i]=max(you[i+1],b[i+k-1]-b[i-1]);
	}
	int maxn=-1e18;
	for(int i=k;i<=n-k;i++){
		maxn=max(maxn,b[i]-b[i-k]+you[i+1]);
	}
	cout<<maxn<<endl;

}
signed main() {
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int oyyo=1;
	cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

小A买彩票

根据题目先给出概率公式:不亏本的数量/总数量。
因为每买一张彩票有4种方法,那么买n张彩票就有4的n次方种方法。
因为每张票3元,所以不亏本的金额范围只能为3n——4n

#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf 0x3f3f3f3f3f3f3f3f3f3f
#define pii pair<int,int>
const int mod=1e9+7;
const int N=200005;

int dp[35][200];

int gcd(int a,int b){
	return b==0?a:gcd(b,a%b); 
}

void solve() {
	int n;
	cin>>n;
	int ans=0;
	dp[0][0]=1;
	
    for(int i=1;i<=n;i++){
		for(int j=i;j<=4*i;j++){
			for(int k=1;k<=4;k++){
				if(j>=k){
					dp[i][j]+=dp[i-1][j-k];
				}
			}
		}
	}

	for(int i=3*n;i<=4*n;i++){
		ans+=dp[n][i];
	}
	
	int sum=pow(4,n);
	int gbs=gcd(ans,sum);
	cout<<ans/gbs<<"/"<<sum/gbs<<endl;
	
}
signed main() {
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int oyyo=1;
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

购物

牛牛的旅游纪念品

这个题如果没有对位置的限制,就可以贪心取前m大的数即可。
但本题的关键在于买的m个物品中任意两个的位置差都大于等于k。那么贪心的方法显而易见行不通,很容易联想到用动态规划。
由题可知本题有两个状态,n个物品以及取走m个物品,并且对物品的位置有着限制,那么我们可以定义
dp[i][j]:前j个物品取i个的欢迎程度
dp[i][j]无非由两种状态转移而来

   1.  没有买第j个物品,那么dp[i][j]=dp[i][j-1]。
   2. 买了第j个物品,那么此时dp[i][j]=dp[i-1][j-k]+a[j]。

很容易得到状态转移 方程:dp[i][j]=max(dp[i][j-1],dp[i-1][j-k]+a[j])。
初始状态就是在取第一个时,dp[1][j]=max(dp[1][j-1],a[j])。

#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf1 0x3f3f3f3f
#define inf2 0x3f3f3f3f3f3f3f3f3f3f
#define pii pair<int,int>
const int mod=1e9+7;
const int N=25;
int dp[105][10005];
void solve() {
	memset(dp,-inf1,sizeof(dp));
	int n,m,k;
	cin>>n>>m>>k;
	vector<int>a(n+1);
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	
	for(int i=1;i<=n;i++){
		dp[1][i]=max(dp[1][i-1],a[i]);
	}
	for(int i=2;i<=m;i++){
		for(int j=k+1;j<=n;j++){
			dp[i][j]=max(dp[i][j-1],dp[i-1][j-k]+a[j]);
		}
	}
	cout<<dp[m][n]<<endl;
}
signed main() {
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int oyyo=1;
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

[NOIP2001]装箱问题

因为每个物体,都有装与不装两种选择,所以我们得到状态转移方程:
f[j]=max(f[j],f[j-w[i]]+w[i]);

f[j] 为:当总容量为 j 时,不放第 i 件物品,所能装的最大体积。
f[j-w[i]]+w[i] 为:当总容量为 j 时,放了第 i 件物品后,所能装的最大体积。(即 j减去第 i 件物品体积 的容量能装的最大体积+第 i 件物品的体积。w[i] 为第 i 件物品体积)

#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
const int N=100005;
const int mod=1e9+7;

int dp[20005];
int a[35];
void solve() {
	int v;
	cin>>v;
	int n;
	cin>>n;
	
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	
	for(int i=1;i<=n;i++){
		for(int j=v;j>=a[i];j--){
			dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
		}
	}
	
	cout<<v-dp[v]<<endl;
}
signed main() {
	ios::sync_with_stdio ( false );cin.tie ( nullptr );cout.tie ( nullptr );
	int oyyo = 1;
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

[NOIP2005]采药

dp[i][j]=max(dp[i-1][j-a[i].t]+a[i].v,dp[i-1][j]);

#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
//#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 3050;
const int mod = 2333;


struct cao{
	int t,v;
};

int dp[105][1005];

void sovle(){
	int t,m;
	cin>>t>>m;
	
	vector<cao>a(m+1);
	
	for(int i=1;i<=m;i++){
		cin>>a[i].t>>a[i].v;
	}
	
	for(int i=1;i<=m;i++){
		for(int j=t;j>=0;j--){
			if(j>=a[i].t){
				dp[i][j]=max(dp[i-1][j],dp[i-1][j-a[i].t]+a[i].v);
			}else{
				dp[i][j]=dp[i-1][j];
            }
		}
	}
	cout<<dp[m][t]<<endl;
	
}

int main()
{    
	//ios::sync_with_stdio(false), cin.tie(0),cout.tie(0); 
	int t = 1;
	//cin>>t;
	while (t--){
		sovle();
	}
	
	return 0;
}

//template<class T>inline void read(T &res)
//{
//	char c;T flag=1;
//	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
//	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
//}

[NOIP2006]开心的金明

定义一个二维数组dp,dp[i][j]表示买到第i个商品(不一定要全买),最多花j元钱。

如果当前的钱可以买就更新状态,否则记录上一次状态。

#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf1 0x3f3f3f3f
#define inf2 0x3f3f3f3f3f3f3f3f3f3f
#define pii pair<int,int>
const int mod=1e9+7;
const int N=25;

struct wu{
	int v;
	int cost;
};

int dp[30][30005];

void solve() {
	
	int n,m;
	cin>>n>>m;
	//总钱数,希望购买的物品的个数。
	vector<wu>a(m+1);
	for(int i=1;i<=m;i++){
		cin>>a[i].cost>>a[i].v;
	}
	
	
	for(int i=1;i<=m;i++){
		for(int j=0;j<=n;j++){
			dp[i][j]=dp[i-1][j];
			if(j>=a[i].cost){
				dp[i][j]=max(dp[i][j],dp[i-1][j-a[i].cost]+a[i].cost*a[i].v);
			}
		}
	}
	cout<<dp[m][n]<<endl;
}
signed main() {
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int oyyo=1;
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

CSL分苹果

重量即价值,背包最大容量就是总容量的一半

#include<bits/stdc++.h>
using namespace std;
#define int  long long
#define endl '\n'
#define inf1 0x3f3f3f3f
#define inf2 0x3f3f3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define PI acos(-1.0)
const int mod=1e9+7;
const int N=25;
int dp[10005];
void solve() {
	int n;
	cin>>n;
	vector<int>a(n+1);
	int sum=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		sum+=a[i];
	}
	
	for(int i=1;i<=n;i++){
	    for(int j=sum/2;j>=a[i];j--){
			dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
		}
	}
	
	cout<<dp[sum/2]<<" "<<sum-dp[sum/2]<<endl;
	
}
signed main() {
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int oyyo=1;
	//cin >> oyyo;
	while ( oyyo-- ) {
		solve();
	}
	return 0;
}

失衡天平

对于每个物品我们都要做出选择:放在天平的左边,放在天平的右边,不选择。
那么我们就可以去找递推式:
dp[i][j]表示前i样物品进行选择后,此时天平两端的重量差为j的时候,最大质量是多少,我们定义这个质量差为 左减右,那么左边放物品质量差增大,右边放质量差变小
(a[i]表示第i件物品的质量)
如果我们选择第i件物品,放在天平的左边,那么dp[i][j]就是从dp[ i -1 ] [ j - a [ i ] ]来的(将第i件物品选择前,质量差为j-a[i])转移过来
同理:如果放在天平的右边,那么dp[i][j]就是dp[i-1][j+a[i]]转移而来的
如果不放,那就是dp[i-1][j]直接转移过来
我们要找到最大的情况,就是上面三个取最大值
dp[i][j] = max(dp [ i -1 ] [ j ] , d p [ i - 1 ][ j - a [ i ] ] + a [ i ] ,d p [ i - 1 ] [j +a [ i] ] + a [ i ] )
因为题目有限定这个质量差的上限,所以最后我们求出这个范围内的最大质量即可
max(sum,dp[n][i])

#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5+7;
const int mod=998244353;
const int inf=LLONG_MAX;
using i128=__int128;
int dp[105][11000];
void sovle(){
	
	memset(dp,-0x3f,sizeof(dp));
	int n,m;
	cin>>n>>m;
	vector<int>a(n+1);
	int sum=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		sum+=a[i];
	}
	
	dp[0][0]=0;
	
	for(int i=1;i<=n;i++){
		for(int j=0;j<=sum;j++){
			dp[i][j]=max(dp[i-1][j],max(dp[i-1][abs(j-a[i])]+a[i],dp[i-1][j+a[i]]+a[i]));
			//初始化为负无穷,因为初始状态f[i][j]的值不一定为0,而应该是一个不存在的值.所以应该是负无穷
		}
	}	
	
	int max1=0;
	for(int i=0;i<=m;i++){
		max1=max(dp[n][i],max1);
	}
	
	cout<<max1<<endl;	
}	
	
signed main()
{	
	ios::sync_with_stdio(false), cin.tie(0),cout.tie(0); 
	int t = 1;
	//cin>>t;
	while (t--){
		sovle();
	}
	
	return 0;
}	

[NOIP2006]金明的预算方案

队伍配置

取数游戏2

石子合并

石子合并

[NOIP2008]传纸条

[NOIP2000]方格取数

[NOIP2010]乌龟棋

[NOIP2006]能量项链

[NOIP2018]货币系统

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1955419.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络轮询器 NetPoller

网络轮询器 NetPoller 网络轮询器是 Go 语言运行时用来处理 I/O 操作的关键组件&#xff0c;它使用了操作系统提供的 I/O 多路复用机制增强程序的并发处理能力。网络轮询器不仅用于监控网络 I/O&#xff0c;还能用于监控文件的 I/O&#xff0c;它利用了操作系统提供的 I/O 多路…

How can I fix my Flask server‘s 405 error that includes OpenAi api?

题意&#xff1a;解决包含OpenAI API的Flask服务器中出现的405错误&#xff08;Method Not Allowed&#xff0c;即方法不允许&#xff09; 问题背景&#xff1a; Im trying to add an API to my webpage and have never used any Flask server before, I have never used Java…

MATLAB进阶:函数和方程

经过前几天的学习&#xff0c;matlab基础我们已经大致了解&#xff0c;现在我们继续学习matlab更进一步的应用。 常用函数 在求解有关多项式的计算时&#xff0c;我们无可避免的会遇到以下几个函数 ypolyval(p,x)&#xff1a;求得多项式p在x处的值y&#xff0c;x可以是一个或…

ComfyUI反推提示词节点报错:Load model failed

&#x1f3a0;报错现象 反推提示词的时候会提示报错&#xff1a; Error occurred when executing WD14Tagger|pysssss: [ONNXRuntimeError] : 3 : NO_SUCHFILE : Load model from F:\ComfyUI-aki\custom_nodes\ComfyUI-WD14-Tagger\models\wd-v1-4-convnext-tagger-v2.onnx fa…

创建mysql库,及webserver使用编译

首先安装mysql sudo apt update sudo apt install mysql-server sudo systemctl status mysql #检查mysql是否安装成功 sudo mysql #进入mysqlSHOW DATABASES; create database yourdb; #创建一个名为yourdb的数据库USE yourdb; #使用刚才创建好的数据库 CREATE TABLE …

Go语言----reflect.DeepEqual函数

在使用go语言进行编程的时候&#xff0c;我们通常会对模块进行测试&#xff0c;在测试的过程中&#xff0c;经常会使用reflect.DeepEqual函数&#xff0c;这个函数是在reflect包中&#xff0c;其提供了运行时反射机制的标准库。其中的reflect.DeepEqual()函数是用来比较两个值是…

【知识梳理】Shell的变量计算

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 Shell中有很多变量的计算&#xff0c;会用到多种运算符。例如这几种&#xff1a; 1. Shell中常见的算术运算符 运算符意义&…

springboot-定时任务源码分析

springboot-定时任务源码分析 前言我们都知道开启 springboot的定时任务需要先使用 EnableScheduling 注解&#xff0c;在可以开启&#xff0c;那么 EnableScheduling 就是定时任务的源头&#xff0c;所以先从 EnableScheduling 开始分析 EnableScheduling 这个注解核心就是…

基于cubeMX的STM32的定时器使用

1、设置cubeMX 这里使用STM32F103RCT6芯片&#xff0c;以定时器2为例&#xff0c;时钟源选择内部时钟 参数设置&#xff0c;预分频7200&#xff0c;定时器周期10000&#xff0c;则表示定时1秒钟 打开定时器2通用中断 其他设置不用修改。时钟页面配置如下 最后生成代码。 2、在…

05.java中常用的类

1.包装类 基本类型包装类booleanBooleancharCharacterbyteByteintIntegerlongLongfloatFloatdoubleDoubleshortShort 从byte开始的包装类都是继承的Number&#xff0c;然后Number继承的object 从byte上面的都是直接继承的oblect (1).装箱和拆箱 装箱&#xff1a;基本类型--…

DSP教学实验箱_数字图像处理操作_案例分享:5-13 灰度图像二值化

一、实验目的 学习灰度图像二值化的原理&#xff0c;掌握图像的读取方法&#xff0c;并实现在LCD上显示二值化前后的图像。 二、实验原理 图像二值化 图像的二值化处理就是将图像上的点的灰度置为 0 或 255&#xff0c;也就是将整个图像呈现出明显的黑白效果。即将 256 个亮…

JAVA零基础学习3(Scanner类,字符串,StringBuilder,StringJoinder,ArrayList成员方法)

JAVA零基础学习&#xff13; Scanner类输入示例代码代码解释完整代码1. 读取字符串2. 读取整数3. 读取浮点数4. 读取布尔值5. 读取单个单词6. 读取长整型数7. 读取短整型数8. 读取字节数注意事项总结 API 字符串解释示例解释解决方法示例&#xff1a;使用 StringBuilder String…

阻塞队列-PriorityBlockQueue

PriorityBlockingQueue 优先级队列不满足FIFO原则它将插入元素进行排序排序的实现是基于数组结构实现的二叉堆排序 二叉堆 在分析优先级别队列时候&#xff0c;需要了解一下二叉堆是什么 二叉堆是一种完全二叉树&#xff0c;除了最底层外&#xff0c;其它层被完全填充。二叉堆…

【AI学习指南】轻量级模型-用 Ollama 轻松玩转本地大模型

目录 探索 最小的AI模型 发现 其他轻量级模型 用 Ollama 轻松玩转本地大模型 本地大模型 Ollama 快速上手 安装 手动安装 下载ollama二进制文件 添加 Ollama 作为启动服务(推荐) 安装 CUDA 驱动程序(可选 - 适用于 Nvidia GPU) 安装 ROCm(可选 - 对于 Radeo…

飞腾2000+/64核芯片ECC功能验证

1、背景介绍 为了排查全国产飞腾计算模块的一个外场问题&#xff0c;需要验证飞腾2000/64核这个处理器的DDR控制器是否支持ECC功能&#xff0c;即在异常情况下能纠错。ECC纠错原理如下&#xff0c;目前飞腾2000/64 DDR控制器就是纠一检二&#xff1a; 2、寄存器说明 目前飞腾…

【学习过程总结】

一、二进制和十进制的转化 1、十进制转化为二进制 2、二进制转化为十进制 二进制转化为十进制这个&#xff0c;对于二进制的数&#xff0c;得从右往左看&#xff08;1《0《1《1&#xff09;。对于下面的转换过程得从下往上看 &#xff08;0、1、2、3&#xff09; 二、按位-异…

原理图----备份

从公司学到的电路图&#xff0c;做一个备份&#xff1a;

用Python做一个翻译软件,比上浏览器快100倍

简单的用Python来做一个翻译软件 开发环境 Python 3.10 Pycharm模块使用 requests -> pip install requests hashlib tkinter案例分为三部分: 1. 爬虫: 获取翻译接口, 请求获取翻译结果问题1: 接口抓包分析问题2: 请求需要写cookie问题3: 不同文本翻译, s加密参数2. 界面…

昇思25天学习打卡营第3天|基础知识-数据集Dataset

目录 环境 环境 导包 数据集加载 数据集迭代 数据集常用操作 shuffle map batch 自定义数据集 可随机访问数据集 可迭代数据集 生成器 MindSpore提供基于Pipeline的数据引擎&#xff0c;通过数据集&#xff08;Dataset&#xff09;和数据变换&#xff08;Transfor…

小模型狂飙!6家巨头争相发布小模型,Andrej Karpathy:大语言模型的尺寸竞争正在倒退...

过去一周&#xff0c;可谓是小模型战场最疯狂的一周&#xff0c;商业巨头改变赛道&#xff0c;向大模型say byebye~。 OpenAI、Apple、Mistral等“百花齐放”&#xff0c;纷纷带着自家性能优越的轻量化小模型入场。 小模型(SLM)&#xff0c;是相对于大语言模型&#xff08;LLM…