2.5学习总结

2.5
1.传纸条
2.装箱问题
3.开心的金明
4.传球游戏
5.修改数组
6.对局匹配
7.刷题统计

传纸条https://www.luogu.com.cn/problem/P1006

题目描述

小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排坐成一个 �m 行 �n 列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的是,他们可以通过传纸条来进行交流。纸条要经由许多同学传到对方手里,小渊坐在矩阵的左上角,坐标 (1,1)(1,1),小轩坐在矩阵的右下角,坐标 (�,�)(m,n)。从小渊传到小轩的纸条只可以向下或者向右传递,从小轩传给小渊的纸条只可以向上或者向左传递。

在活动进行中,小渊希望给小轩传递一张纸条,同时希望小轩给他回复。班里每个同学都可以帮他们传递,但只会帮他们一次,也就是说如果此人在小渊递给小轩纸条的时候帮忙,那么在小轩递给小渊的时候就不会再帮忙。反之亦然。

还有一件事情需要注意,全班每个同学愿意帮忙的好感度有高有低(注意:小渊和小轩的好心程度没有定义,输入时用 00 表示),可以用一个 [0,100][0,100] 内的自然数来表示,数越大表示越好心。小渊和小轩希望尽可能找好心程度高的同学来帮忙传纸条,即找到来回两条传递路径,使得这两条路径上同学的好心程度之和最大。现在,请你帮助小渊和小轩找到这样的两条路径。

输入格式

第一行有两个用空格隔开的整数 �m 和 �n,表示班里有 �m 行 �n 列。

接下来的 �m 行是一个 �×�m×n 的矩阵,矩阵中第 �i 行 �j 列的整数表示坐在第 �i 行 �j 列的学生的好心程度。每行的 �n 个整数之间用空格隔开。

输出格式

输出文件共一行一个整数,表示来回两条路上参与传递纸条的学生的好心程度之和的最大值。

输入输出样例

输入 #1复制

3 3
0 3 9
2 8 5
5 7 0

输出 #1复制

34

说明/提示

【数据范围】

对于 30%30% 的数据,满足 1≤�,�≤101≤m,n≤10。
对于 100%100% 的数据,满足 1≤�,�≤501≤m,n≤50。

思路:动态规划,模拟两条不相交的路径,每走一步都有四种情况:

1.第一张纸条向下传,第二张纸条向下传;

2.第一张纸条向下传,第二张纸条向右传;

3.第一张纸条向右传,第二张纸条向下传;

4.第一张纸条向右传,第二张纸条向右传;

给走的方向加一些限定,就可以形成不相交的两条路径:

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long 
int a[55][55],dp[55][55][55][55];
int m,n;
int maxn(int a,int b,int c,int d){
	return max(a,b)>max(c,d)?max(a,b):max(c,d);
}
signed main(){
	cin>>m>>n;
	for (int i=1;i<=m;++i){
		for (int j=1;j<=n;++j){
			cin>>a[i][j];
		}
	}
	for (int i=1;i<=m;++i){
		for (int j=1;j<=n;++j){
			for (int k=i+1;k<=m;++k){
				for (int l=1;l<j;++l){
					dp[i][j][k][l]=maxn(dp[i-1][j][k-1][l],dp[i][j-1][k][l-1],dp[i-1][j][k][l-1],dp[i][j-1][k-1][l])+a[i][j]+a[k][l];
				}
			}
		}
	}
	cout<<dp[m-1][n][m][n-1];
}

装箱问题https://www.luogu.com.cn/problem/P1049

题目描述

有一个箱子容量为 �V,同时有 �n 个物品,每个物品有一个体积。

现在从 �n 个物品中,任取若干个装入箱内(也可以不取),使箱子的剩余空间最小。输出这个最小值。

输入格式

第一行共一个整数 �V,表示箱子容量。

第二行共一个整数 �n,表示物品总数。

接下来 �n 行,每行有一个正整数,表示第 �i 个物品的体积。

输出格式

  • 共一行一个整数,表示箱子最小剩余空间。

输入输出样例

输入 #1复制

24
6
8
3
12
7
9
7

输出 #1复制

0

说明/提示

对于 100%100% 数据,满足 0<�≤300<n≤30,1≤�≤200001≤V≤20000。

思路:动态规划,01背包问题,把v当做是背包的总共 容量,而物品的体积也是物品的价值,找到在背包容量为v的情况下,前n个物品可以形成的最大价值,然后减去背包容量就是最小剩余容量

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long 
int a[35],dp[20005];
int v,n;
signed main(){
	cin>>v>>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];
}

开心的金明https://www.luogu.com.cn/problem/P1060

题目描述

金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过 �N 元钱就行”。今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的 �N 元。于是,他把每件物品规定了一个重要度,分为 55 等:用整数 1−51−5 表示,第 55 等最重要。他还从因特网上查到了每件物品的价格(都是整数元)。他希望在不超过 �N 元(可以等于 �N 元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

设第�j件物品的价格为 ��vj​,重要度为 ��wj​,共选中了 �k 件物品,编号依次为 �1,�2,…,��j1​,j2​,…,jk​,则所求的总和为:

��1×��1+��2×��2…+���×���vj1​​×wj1​​+vj2​​×wj2​​…+vjk​​×wjk​​。

请你帮助金明设计一个满足要求的购物单。

输入格式

第一行,为 22 个正整数,用一个空格隔开:�,�n,m(�<30000,�<25n<30000,m<25)其中 �n 表示总钱数,�m 为希望购买物品的个数。

从第 22 行到第 �+1m+1 行,第 �j 行给出了编号为 �−1j−1 的物品的基本数据,每行有 22 个非负整数 �,�v,p(其中 �v 表示该物品的价格 (�≤10000)(v≤10000),�p 表示该物品的重要度(1≤�≤51≤p≤5)。

输出格式

11 个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<100000000<100000000)。

输入输出样例

输入 #1复制

1000 5
800 2
400 5
300 5
400 3
200 2

输出 #1复制

3900

思路:总的背包容量为总金额,每个物品的价格就是单个物品的容量,乘上重要度就是这个物品的价值

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long 
int a[35],v[35],dp[30005];
int n,m;
signed main(){
	cin>>n>>m;
	for (int i=1;i<=m;++i){
			cin>>a[i]>>v[i];
	}
	for (int i=1;i<=m;++i){
		for (int j=n;j>=a[i];--j){
			dp[j]=max(dp[j],dp[j-a[i]]+a[i]*v[i]);
		}
	}
	cout<<dp[n];
}

传球游戏https://www.luogu.com.cn/problem/P1057

题目描述

上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。

游戏规则是这样的:�n 个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再次吹哨子时,传球停止,此时,拿着球没有传出去的那个同学就是败者,要给大家表演一个节目。

聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了 �m 次以后,又回到小蛮手里。两种传球方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有三个同学 11 号、22 号、33 号,并假设小蛮为 11 号,球传了 33 次回到小蛮手里的方式有 1→2→3→11→2→3→1 和 1→3→2→11→3→2→1,共 22 种。

输入格式

一行,有两个用空格隔开的整数 �,�(3≤�≤30,1≤�≤30)n,m(3≤n≤30,1≤m≤30)。

输出格式

11 个整数,表示符合题意的方法数。

输入输出样例

输入 #1复制

3 3

输出 #1复制

2

说明/提示

数据范围及约定

  • 对于 40%40% 的数据,满足:3≤�≤30,1≤�≤203≤n≤30,1≤m≤20;
  • 对于 100%100% 的数据,满足:3≤�≤30,1≤�≤303≤n≤30,1≤m≤30。

思路:dp[i][j]表示了经过j次传球传到第i个人的次数,由于是成环的,所以第一个人和最后一个人需要特判,对于第i个人,可以有前面和后面两个人传过来,对于次数j,是由j-1次转移来的

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long 
int a[35],dp[35][35];
int n,m;
signed main(){
	cin>>n>>m;
	dp[1][0]=1;
	for (int i=1;i<=m;++i){
		dp[1][i]=dp[n][i-1]+dp[2][i-1];
		dp[n][i]=dp[n-1][i-1]+dp[1][i-1];
		for (int j=2;j<n;++j){
			dp[j][i]=dp[j-1][i-1]+dp[j+1][i-1];
		}
	}
	cout<<dp[1][m];
}

修改数组https://www.luogu.com.cn/problem/P8686

题目描述

给定一个长度为 �N 的数组 �=[�1,�2,⋯��]A=[A1​,A2​,⋯AN​],数组中有可能有重复出现的整数。

现在小明要按以下方法将其修改为没有重复整数的数组。小明会依次修改 �2,�3,⋯ ,��A2​,A3​,⋯,AN​。

当修改 ��Ai​ 时,小明会检查 ��Ai​ 是否在 �1A1​ ∼ ��−1Ai−1​ 中出现过。如果出现过,则小明会给 ��Ai​ 加上 11;如果新的 ��Ai​ 仍在之前出现过,小明会持续给 ��Ai​ 加 11,直到 ��Ai​ 没有在 �1A1​ ∼ ��−1Ai−1​ 中出现过。

当 ��AN​ 也经过上述修改之后,显然 �A 数组中就没有重复的整数了。

现在给定初始的 �A 数组,请你计算出最终的 �A 数组。

输入格式

第一行包含一个整数 �N。

第二行包含 �N 个整数 �1,�2,⋯ ,��A1​,A2​,⋯,AN​。

输出格式

输出 �N 个整数,依次是最终的 �1,�2,⋯ ,��A1​,A2​,⋯,AN​。

输入输出样例

输入 #1复制

5
2 1 1 3 4

输出 #1复制

2 1 3 4 5

说明/提示

对于 80%80% 的评测用例,1≤�≤100001≤N≤10000。

对于所有评测用例,1≤�≤1051≤N≤105,1≤��≤1061≤Ai​≤106。

思路:使用并查集的方法,每输入一个数a,就输出它的根节点find(a),然后把a的根节点和a的根节点+1合并起来

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long 
int n,f[1000005];
int find(int x){
	if (f[x]==x)return x;
	else{
		f[x]=find(f[x]);
		return f[x];
	}
}
void unionn(int i,int j){
	f[find(i)]=find(j);
}
signed main(){
	cin>>n;
	for (int i=1;i<=100005;++i){
		f[i]=i;
	}
	for (int i=1;i<=n;++i){
		int x;
		cin>>x;
		cout<<find(x)<<" ";
		unionn(find(x),find(x)+1);
	}
}

对局匹配https://www.luogu.com.cn/problem/P8656

题目描述

小明喜欢在一个围棋网站上找别人在线对弈。这个网站上所有注册用户都有一个积分,代表他的围棋水平。

小明发现网站的自动对局系统在匹配对手时,只会将积分差恰好是 �K 的两名用户匹配在一起。如果两人分差小于或大于 �K,系统都不会将他们匹配。

现在小明知道这个网站总共有 �N 名用户,以及他们的积分分别是 �1,�2,⋯��A1​,A2​,⋯AN​。

小明想了解最多可能有多少名用户同时在线寻找对手,但是系统却一场对局都匹配不起来(任意两名用户积分差不等于 �K)?

输入格式

第一行包含两个个整数 �N 和 �K。

第二行包含 �N 个整数 �1,�2,⋯ ,��A1​,A2​,⋯,AN​。

输出格式

一个整数,代表答案。

输入输出样例

输入 #1复制

10 0
1 4 2 8 5 7 1 4 2 8

输出 #1复制

6

输入 #2复制

10 1
2 1 1 1 1 4 4 3 4 4

输出 #2复制

8

说明/提示

对于 30%30% 的数据,1≤�≤101≤N≤10。

对于 100%100% 的数据,1≤�≤1051≤N≤105,0≤�,��≤1050≤K,Ai​≤105 。

思路:把所有积分相同的人数加起来,并判断两种情况k是否等于0

如果等于0,那么记录积分的种类,就是答案,因为每个种类的积分就放一个人,是不能比赛的

如果不等于0,就把相差k的积分的人数相减,最后加起来就是答案

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long 
const int N=1e5+5;
int n,k,a[N],s[N];
signed main(){
	cin>>n>>k;
	for (int i=0;i<n;++i){
		int x;
		cin>>x;
		s[x]++;
	}
	if (k==0){
		int cnt=0;
		for (int i=0;i<=N;++i){
			if (s[i]!=0)cnt++;
		}
		cout<<cnt;
		return 0;
	}else if (k!=0){
		for (int i=0;i<=N-k;++i){
			if (s[i]<s[i+k]) s[i+k]-=s[i];
			else s[i+k]=0;
		}
	}
	int cnt=0;
	for (int i=0;i<N;++i){
		cnt+=s[i];
	}
	cout<<cnt;
}

刷题统计https://www.luogu.com.cn/problem/P8780

题目描述

小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 �a 道题目,周六和周日每天做 �b 道题目。请你帮小明计算,按照计划他将在第几天实现做题数大于等于 �n 题?

输入格式

输入一行包含三个整数 �,�a,b 和 �n.

输出格式

输出一个整数代表天数。

输入输出样例

输入 #1复制

10 20 99

输出 #1复制

8

说明/提示

对于 50%50% 的评测用例,1≤�,�,�≤1061≤a,b,n≤106.

对于 100%100% 的评测用例,1≤�,�,�≤10181≤a,b,n≤1018.

#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x& - (x))
#define int long long 
signed main(){
	int n,m,k;
	cin>>n>>m>>k;
	int week=n*5+m*2;
	int day=(k/week)*7;
	k %=week;
	if (k<=n*5) day+=k/n+(k%n==0 ? 0:1);
	else {
		day+=5; k-=5*n;
		day+=k/m+(k%m==0 ? 0:1); 
	}
	cout<<day;
}
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值