第十三届蓝桥杯C++B组j国赛

news2024/11/24 2:49:24

第十三届蓝桥杯C++组

题目 2693:

蓝桥杯2022年第十三届决赛真题-卡牌

题目描述

这天,小明在整理他的卡牌。

他一共有 n 种卡牌,第 i 种卡牌上印有正整数数 i(i ∈ [1, n]),且第 i 种卡牌 现有 ai 张。

而如果有 n 张卡牌,其中每种卡牌各一张,那么这 n 张卡牌可以被称为一 套牌。小明为了凑出尽可能多套牌,拿出了 m 张空白牌,他可以在上面写上数 i,将其当做第 i 种牌来凑出套牌。然而小明觉得手写的牌不太美观,决定第 i 种牌最多手写 bi 张。

请问小明最多能凑出多少套牌?

输入格式

输入共 3 行,第一行为两个正整数 n, m。

第二行为 n 个正整数 a1, a2, …, an。

第三行为 n 个正整数 b1, b2, …, bn。

输出格式

一行,一个整数表示答案。

样例输入

4 5
1 2 3 4
5 5 5 5

样例输出

3

提示

这 5 张空白牌中,拿 2 张写 1,拿 1 张写 2,这样每种牌的牌数就变为了 3, 3, 3, 4,可以凑出 3 套牌,剩下 2 张空白牌不能再帮助小明凑出一套。

对于 30% 的数据,保证 n ≤ 2000 ;

对于 100% 的数据,保证 n ≤ 2 × 10^5 ; ai , bi ≤ 2n; m ≤ n2 。

听典的一个题,直接二分就行了

#include <iostream>
#include<vector>
#include<map>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll N = 2e5 + 10;
const ll mod = 1e9 + 7;
ll a[N],b[N]; 
ll n,m;
bool check(ll mid){
	ll sum=0;
	for(int i=1;i<=n;i++){
		if(a[i]<mid)
		if(mid-a[i]<=b[i])
		sum+=mid-a[i];
		else
		return false;
		if(sum>m)
		return false;
	}
	return true;
}
void solve()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	for(int j=1;j<=n;j++)
	cin>>b[j];
	ll l=0,r=N*N;
	while(l<r){
		ll mid=l+r>>1;
		if(check(mid))
		l=mid+1;
		else
		r=mid;
	}
	cout<<r-1<<'\n';
}

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

题目 2694:

蓝桥杯2022年第十三届决赛真题-最大数字

题目描述

给定一个正整数 N。你可以对 N 的任意一位数字执行任意次以下 2 种操作:

  1. 将该位数字加 1。如果该位数字已经是 9,加 1 之后变成 0。

  2. 将该位数字减 1。如果该位数字已经是 0,减 1 之后变成 9。

你现在总共可以执行 1 号操作不超过 A 次,2 号操作不超过 B 次。

请问你最大可以将 N 变成多少?

输入格式

第一行包含 3 个整数:N, A, B。

输出格式

一个整数代表答案。

样例输入

123 1 2

样例输出

933

提示

对百位数字执行 2 次 2 号操作,对十位数字执行 1 次 1 号操作。

对于 30% 的数据,1 ≤ N ≤ 100; 0 ≤ A, B ≤ 10

对于 100% 的数据,1 ≤ N ≤ 10^17; 0 ≤ A, B ≤ 100

考虑数据范围,复杂度只和位数有关,首先贪心,尽量让前面的数变大,当然变大可以减法或者加法两种操作,因此复杂度大概在2^17左右,需要注意的地方就是如果减法剩余次数不能使得数字变大的话,就不需要进行减法操作。

#include <iostream>
#include<vector>
#include<map>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll N = 2e5 + 10;
const ll mod = 1e9 + 7;
ll ans=0;
void dfs(string s,int pos,int a,int b){
	if(pos==s.size()||a==0&&b==0){
		ll sum=0;
		for(int i=0;i<s.size();i++)
		sum=sum*10+s[i]-'0';
		ans=max(ans,sum);
		return ;
	}
	int d1='9'-s[pos],d2=s[pos]-'0'+1;
	if(a>0){
		string s1=s;
		s1[pos]+=min(a,d1);
		dfs(s1,pos+1,a-min(a,d1),b);
	}
	if(b>=d2){
		string s1=s;
		s1[pos]='9';
		dfs(s1,pos+1,a,b-d2);
	}
	dfs(s,pos+1,a,b);
}
void solve()
{
	string s;
	int a,b;
	cin>>s>>a>>b;
	dfs(s,0,a,b);
	cout<<ans<<'\n';
}

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

题目 2695:

蓝桥杯2022年第十三届决赛真题-出差

题目描述

A 国有 N 个城市,编号为 1 . . . N。小明是编号为 1 的城市中一家公司的员工,今天突然接到了上级通知需要去编号为 N 的城市出差。

由于疫情原因,很多直达的交通方式暂时关闭,小明无法乘坐飞机直接从城市 1 到达城市 N,需要通过其他城市进行陆路交通中转。小明通过交通信息网,查询到了 M 条城市之间仍然还开通的路线信息以及每一条路线需要花费的时间。

同样由于疫情原因,小明到达一个城市后需要隔离观察一段时间才能离开该城市前往其他城市。通过网络,小明也查询到了各个城市的隔离信息。(由于小明之前在城市 1,因此可以直接离开城市 1,不需要隔离)

由于上级要求,小明希望能够尽快赶到城市 N,因此他求助于你,希望你能帮他规划一条路线,能够在最短时间内到达城市 N。

输入格式

第 1 行:两个正整数 N, M, N 表示 A 国的城市数量,M 表示未关闭的路线数量

第 2 行:N 个正整数,第 i 个整数 Ci 表示到达编号为 i 的城市后需要隔离的时间

第 3 . . . M + 2 行:每行 3 个正整数,u, v, c,表示有一条城市 u 到城市 v 的双向路线仍然开通着,通过该路线的时间为 c

输出格式

第 1 行:1 个正整数,表示小明从城市 1 出发到达城市 N 的最短时间(到达城市 N,不需要计算城市 N 的隔离时间)

样例输入

4 4
5 7 3 4
1 2 4
1 3 5
2 4 3
3 4 5

样例输出

13

提示

img

路线 1:1 -> 2 -> 4,时间为 4+7(隔离)+3=14

路线 2:1 -> 3 -> 4,时间为 5+3(隔离)+5=13

对于 100% 的数据,1 ≤ N ≤ 1000 , 1 ≤ M ≤ 10000, 1 ≤ Ci ≤ 200, 1 ≤ u, v ≤ N, 1 ≤ c ≤ 1000

在以某个点为起点的边上加上延迟然后跑一遍最短路就可以了,注意cpp的堆是大根堆,又一次忘记开了,要是实际比赛这直接jiji

#include <iostream>
#include<vector>
#include<map>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll N = 1e3 + 10;
const ll mod = 1e9 + 7;
vector<int>g[N],w[N];
int c[N],d[N];
bool vis[N];
int dij(int s,int end){
	priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q;
	q.push({0,s});
	while(!q.empty()){
		int t=q.top().first,u=q.top().second;
		q.pop();
		if(vis[u])continue;
		d[u]=t;
		vis[u]=true;
		if(u==end)
		return t;
		for(int i=0;i<w[u].size();i++){
			if(!vis[g[u][i]])
			q.push({w[u][i]+d[u],g[u][i]});
		}
	}
	return d[end];
}
void solve()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	cin>>c[i];
	int u,v,x;
	for(int i=1;i<=m;i++){
	cin>>u>>v>>x;
	g[u].push_back(v);
	g[v].push_back(u);
	w[u].push_back(x);
	w[v].push_back(x);
	}
	for(int i=2;i<=n;i++)
	for(int j=0;j<g[i].size();j++)
	w[i][j]+=c[i];
	cout<<dij(1,n)<<'\n';
}

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

题目 2696:

蓝桥杯2022年第十三届决赛真题-费用报销

题目描述

小明在出差结束后返回了公司所在的城市,在填写差旅报销申请时,粗心的小明发现自己弄丢了出差过程中的票据。

为了弥补小明的损失,公司同意小明用别的票据进行报销,但是公司财务要求小明提交的票据中任意两张的日期差不小于 K 天,且总金额不得超过实际差旅费用 M。

比如财务要求 K = 7 时,若小明提交了一张 1 月 8 日的票据,小明就不能提交 1 月 2 日至 1 月 14 日之间的其他票据,1 月 1 日及之前和 1 月 15 日及之后的票据则可以提交。

公司的同事们一起给小明凑了 N 张票据,小明现在想要请你帮他整理一下,从中选取出符合财务要求的票据,并使总金额尽可能接近 M。

需要注意,由于这些票据都是同一年的,因此 12 月底的票据不会影响到 1 月初票据的提交。这一年不是闰年。

输入格式

第 1 行:3 个整数,N, M, K

第 2 . . . N + 1 行:每行 3 个整数 mi , di , vi,第 i + 1 行表示第 i 张票据时间的月份 mi 和日期 di,vi 表示该票据的面值

输出格式

第 1 行:1 个整数,表示小明能够凑出的最大报销金额

样例输入

4 16 3
1 1 1
1 3 2
1 4 4
1 6 8

样例输出

10

提示

选择 1 月 3 日和 1 月 6 日的票据

对于 100% 的评测用例,1 ≤ N ≤ 1000, 1 ≤ M ≤ 5000, 1 ≤ K ≤ 50, 1 ≤ mi ≤ 12, 1 ≤ di ≤ 31, 1 ≤ vi ≤ 400

日期保证合法。

动态规划,dp[i] [j]表示选前i种票据且总票据金额不超过j的可获得的最大金额,因为还需要保证选取第i种票据时在它前面k天以内的票据不能存在,所以还要保证转移时的i1票据所在的日期要满足要求,这个地方二分一下就可以了

#include <iostream>
#include<vector>
#include<map>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll N = 1e3 + 10;
const ll mod = 1e9 + 7;
struct node{
	int day;
	int money;
	bool operator<(const node&a){
		return day<a.day;
	}
}p[N];
int d[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int dp[N][5*N];//选前i种且总金额不超过j的最大金额 
void solve()
{
	for(int i=2;i<=12;i++)
	d[i]+=d[i-1];
	int n,m,k;
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++){
		int a,b,c;
		cin>>a>>b>>c;
		b+=d[a-1];
		p[i]={b,c};
	}
	sort(p+1,p+1+n);
	int ans=0;
	for(int i=1;i<=n;i++){
	for(int j=1;j<=m;j++){
		if(j<p[i].money){
		dp[i][j]=dp[i-1][j]; 
		continue;
	}
		int c=p[i].day-k;
		int l=1,r=i+1;
		while(l<r){
			int mid=l+r>>1;
			if(p[mid].day<=c)
			l=mid+1;
			else
			r=mid;
		}
		r--;
		dp[i][j]=max(dp[i-1][j],dp[r][j-p[i].money]+p[i].money);
	}
	ans=max(ans,dp[i][m]);
}
cout<<ans<<'\n';
}

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

题目 2697:

蓝桥杯2022年第十三届决赛真题-故障

题目描述

在软件或系统开发中,我们会遇到各种各样的故障。为了从故障现象反推故障原因,工程师们会总结一种叫做相关性矩阵的二维表格,来表示故障原因与故障现象之间的关系。比如:

蓝桥杯2022年第十三届决赛真题-故障

其中每行表示一种故障原因,每一列表示一种故障现象。该矩阵表示故障原因 A 可能产生故障现象 2、3、4,故障原因 B 可能产生故障现象 1、3。

在实际开发过程中,如果出现了故障原因,工程师就可以根据故障现象,去计算每种故障原因产生的概率,并按照概率大小对故障原因进行排查,以达到快速定位故障原因的目的。

现在,我们假设系统开发中同一时间只会出现一种故障原因,并且故障原因引起各故障现象是独立事件。举个例子来说:

假设系统现在发生了故障原因 A,有 1/3 的概率出现故障现象 2,有 1/4 的概率出现故障现象 3,有 1/2 的概率出现故障现象 4。由于 3 种现象是独立发生的,因此有1/(234)的概率同时出现故障 2、3、4。

约定若相关性矩阵中没有 ‘x’ 记号,则表示该故障原因一定不会产生某故障现象,比如故障原因 A,一定不会产生故障现象 1。

根据历史经验数据,我们统计得到了每一种故障原因出现的概率以及每一 种故障原因对应的故障现象产生概率。

现在已知系统出现的故障现象,求问各个故障原因发生的概率。

输入格式

第 1 行:2 个正整数 N, M,N 表示故障原因的个数(编号 1 . . . N),M 表示故障现象的个数(编号 1 . . . M).

第 2 行:N 个整数,第 i 个数表示故障原因 i 产生的概率 Pi .

第 3 . . . N + 2 行:每行 M 个整数,第 i + 2 行第 j 个整数 Pij 表示故障原因 i 出现故障现象 j 的概率(百分比).

第 N + 3 行:1 个正整数 K,表示目前出现的故障现象数量。

第 N + 4 行:K 个正整数,依次为当前出现的故障现象编号,不会重复。

输出格式

第 1 . . . N 行:按概率从高到低输出每种故障原因及其可能的概率,若出现概率相同则优先输出编号小的故障原因。第 1 个数为故障原因编号,第 2 个数为故障概率(百分比),保留 2 位小数。

样例输入

3 5
30 20 50
0 50 33 25 0
30 0 35 0 0
0 0 0 25 60
1
3

样例输出

2 56.89
1 43.11
3 0.00

提示

对于所有测试用例,1 ≤ N ≤ 40, 1 ≤ M ≤ 20, 0 ≤ Pi ≤ 100, ∑ (Pi) = 100, 0 ≤ Pij ≤ 100.

概率学的太烂了,就会一点点简单数论和组合数学,贝叶斯公式不会,贴一份别人的题解
用100减去未出现的现象的对应故障的概率。
令各个现象为Ri, 故障为A,B,C…
则P(R1R2R3..Rm|A) = P(R1|A) * P(R2|A) … * P(Rm|A)
再带入贝叶斯公示就好了。
注意开long double,而且注意浮点数比较时的精度问题。

#include <stdio.h>
#include <algorithm>
#include <math.h>
#include<iostream>
using namespace std;
const double esp = 1e-12;
int n, m, k, P[50][31];
struct node {
    long double p;
    int i;
    inline bool operator<(const node &nd) const 
    {
        return (abs(p - nd.p) < esp) ? i < nd.i : p > nd.p;
    }
} ans[50];
int main() 
{
    scanf("%d %d", &n, &m);
    for (int i = 0; i < n; ++i)
        scanf("%d", &P[i][0]);
    for (int i = 0; i < n; ++i)
        for (int j = 1; j <= m; ++j)
            scanf("%d", &P[i][j]), P[i][j] = 100 - P[i][j];
    scanf("%d", &k);
    for (int g = 0, j; g < k; ++g) 
    {
        scanf("%d", &j);
        for (int i = 0; i < n; ++i)
            P[i][j] = 100 - P[i][j];
    }
    long double sum = 0;
    for (int i = 0; i < n; ++i) 
    {
        ans[i].p = P[i][0] / 100.0;
        for (int j = 1; j <= m; ++j)
            ans[i].p *= P[i][j] / 100.0;
        ans[i].i = i + 1;
        sum += ans[i].p;
    }
    sort(ans, ans + n);
    for (int i = 0; i < n; ++i)
    {
        long double t = (abs(sum) < esp) ? 0.0 : 100 * ans[i].p / sum;
        printf("%d %.2LF\n", ans[i].i, t);
    }
       return 0;
}

题目 2698:

蓝桥杯2022年第十三届决赛真题-机房

题目描述

这天,小明在机房学习。

他发现机房里一共有 n 台电脑,编号为 1 到 n,电脑和电脑之间有网线连接,一共有 n − 1 根网线将 n 台电脑连接起来使得任意两台电脑都直接或者间接地相连。

小明发现每台电脑转发、发送或者接受信息需要的时间取决于这台电脑和多少台电脑直接相连,而信息在网线中的传播时间可以忽略。比如如果某台电脑用网线直接连接了另外 d 台电脑,那么任何经过这台电脑的信息都会延迟 d 单位时间 (发送方和接收方也会产生这样的延迟,当然如果发送方和接收方都是同一台电脑就只会产生一次延迟)。

小明一共产生了 m 个疑问:如果电脑 ui 向电脑 vi 发送信息,那么信息从 ui 传到 vi 的最短时间是多少?

输入格式

输入共 n + m 行,第一行为两个正整数 n, m。

后面 n − 1 行,每行两个正整数 x, y 表示编号为 x 和 y 的两台电脑用网线直接相连。

后面 m 行,每行两个正整数 ui , vi 表示小明的第 i 个疑问。

输出格式

输出共 m 行,第 i 行一个正整数表示小明第 i 个疑问的答案。

样例输入

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

样例输出

5
6
1

提示

这四台电脑各自的延迟分别为 2, 2, 1, 1。

对于第一个询问,从 2 到 3 需要经过 2, 1, 3,所以时间和为 2 + 2 + 1 = 5。

对于第二个询问,从 3 到 4 需要经过 3, 1, 2, 4,所以时间和为 1+2+2+1 = 6。

对于第三个询问,从 3 到 3 只会产生一次延迟,所以时间为 1。

对于 30% 的数据,保证 n, m ≤ 1000;

对于 100% 的数据,保证 n, m ≤ 100000 。

思路很简单,先建图后建树,然后跑lca,求lca的过程中顺便把延迟之和求出来,注意要加上终点的延迟

这题wa了几次,st预处理的时候i,j不分wa了,还是熟练度不太高

#include <iostream>
#include<vector>
#include<map>
#include<string>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll N = 1e5 + 10;
const ll mod = 1e9 + 7;
int fa[N] = { 0,1 }, depth[N];
pair<int, int>st[N][15];

vector<int>g[N];
void init(int f, int root) {
	depth[root] = depth[f] + 1;
	fa[root] = f;
	st[root][0] = { g[root].size(),f };
	for (int i = 0; i < g[root].size(); i++) {
		if (g[root][i] != f)
			init(root, g[root][i]);
	}
}
int lca(int u, int v) {
	if (u == v)
		return g[u].size();
	int ans = 0;
	for (int i = 14; i >= 0; i--) {
		if (st[u][i].second != st[v][i].second) {
			ans += st[u][i].first + st[v][i].first, u = st[u][i].second, v = st[v][i].second;
		}
	}
	ans += st[u][0].first + st[v][0].first + g[st[u][0].second].size();
	return ans;
}
void solve()
{
	int n, m;
	cin >> n >> m;
	int u, v;
	for (int i = 1; i < n; i++)
		cin >> u >> v, g[u].push_back(v), g[v].push_back(u);
	init(0, 1);
	for (int i = 1; i <= 14; i++)
		for (int j = 1; j <= n; j++)
			st[j][i] = { st[j][i - 1].first + st[st[j ][i-1].second][i - 1].first,st[st[j][i - 1].second][i - 1].second };
	while (m--) {
		cin >> u >> v;
		int a = u, b = v;
		if (depth[u] < depth[v])
			swap(u, v);
		int x = depth[u] - depth[v], ans = 0;
		for (int i = 0; i <= 14 && x; i++) {
			if (x & 1) {
				ans += st[u][i].first;
				u = st[u][i].second;
			}
			x >>= 1;
		}
		ans += lca(u, v);
		cout << ans << '\n';
	}
}

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


题目 2699:

蓝桥杯2022年第十三届决赛真题-齿轮

题目描述

这天,小明在组装齿轮。

他一共有 n 个齿轮,第 i 个齿轮的半径为 ri,他需要把这 n 个齿轮按一定顺序从左到右组装起来,这样最左边的齿轮转起来之后,可以传递到最右边的齿轮,并且这些齿轮能够起到提升或者降低转速 (角速度) 的作用。

蓝桥杯2022年第十三届决赛真题-齿轮

小明看着这些齿轮,突然有 Q 个疑问:能否按一定顺序组装这些齿轮使得最右边的齿轮的转速是最左边的齿轮的 qi 倍?

输入格式

输入共 Q + 2 行,第一行为两个正整数 n, Q,表示齿轮数量和询问数量。

第二行为 n 个正整数 r1,r2, …,rn,表示每个齿轮的半径。

后面 Q 行,每行一个正整数 qi 表示询问。

输出格式

Q 行,对于每个询问,如果存在至少一种组装方案满足条件,输出 ‘YES‘,否则输出 ‘NO‘。

样例输入

5 3
4 2 3 3 1
2
4
6

样例输出

YES
YES
NO

提示

询问 1 方案之一:2 3 3 4 1 。

询问 2 方案之一:4 2 3 3 1 。

询问 3 没有方案。

对于 15% 的数据,保证 n, Q ≤ 100 ;

对于 30% 的数据,保证 n, Q ≤ 2000 ;

对于 100% 的数据,保证 n, Q ≤ 2 × 105 ; ri , qi ≤ 2 × 105 。

很容易知道的就是倍数只和头尾转轮有关,所以问题转换成了序列中是否存在两个数a,b使得a/b=x。思路是先预处理一下有哪些x存在,然后查询直接看存不存在这个x就行了。预处理的话,先排序然后对于每个ai,分解因数,看一下这个因数是否在a数组中出现过,假设因子为j,需要判断(ai)/j是否在数组中存在,如果存在就x=j,同时如果j在数组中存在,那么存在x=(ai)/j,复杂度n^1.5。

刚开始写的时候没有想着直接分解因数,而是采取了类似筛法的思路,在dotcpp上面过了,后面觉得有点懵,因为我认为时间复杂度说不去的,后面跑到蓝桥杯官网交了一发,也在规定时间内跑完,但20发数据wa了一发小数据,对了95%,也不知道哪里错了,不过时间复杂度可以过就觉得蛮离谱的

95%的错误代码

#include <iostream>
#include<vector>
#include<map>
#include<string>
#include<map>
#include<queue>
#include<algorithm>
#include<unordered_map>
using namespace std;
typedef long long ll;
const ll N = 2e5 + 10;
const ll mod = 1e9 + 7;
void solve()
{
	int n,q;
	cin>>n>>q;
	int x;
	unordered_map<int,int>mp;
	unordered_map<int,int>ans;
	for(int i=1;i<=n;i++){
	cin>>x,mp[x]++;
	if(mp[x]>=2)
	ans[1]++;
}
	for(auto it:mp){
		for(int i=2;i*it.first<N;i++)
		if(mp[i*it.first]>0)
		ans[i]++;
		else
		mp.erase(i*it.first);
	}
	while(q--){
		cin>>x;
		if(ans[x]>0)
		cout<<"YES"<<'\n';
		else
		cout<<"NO"<<'\n';
	}
}

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

正确代码

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

int a[200005];

int main(){
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++){
        int x;
        cin>>x;
        a[x]++;
    }
    while(m--){
        int x;
        cin>>x;
        int f=0;
        for(int i=1;i<=n/x;i++){
            if(a[i]&&a[i*x]){
                if(i!=i*x||i==i*x&&a[i]>1){
                    f=1;
                    break;
                } 
            }
        }
        if(f||(n==1&&x==1)) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
}

题目 2700:

蓝桥杯2022年第十三届决赛真题-搬砖

题目描述

这天,小明在搬砖。

他一共有 n 块砖,他发现第 i 砖的重量为 wi,价值为 vi。他突然想从这些砖中选一些出来从下到上堆成一座塔,并且对于塔中的每一块砖来说,它上面所有砖的重量和不能超过它自身的价值。

他想知道这样堆成的塔的总价值(即塔中所有砖块的价值和)最大是多少。

输入格式

输入共 n + 1 行,第一行为一个正整数 n,表示砖块的数量。

后面 n 行,每行两个正整数 wi , vi 分别表示每块砖的重量和价值。

输出格式

一行,一个整数表示答案。

样例输入

5
4 4
1 1
5 2
5 5
4 3

样例输出

10

提示

选择第 1、2、4 块砖,从上到下按照 2、1、4 的顺序堆成一座塔,总价值为 4 + 1 + 5 = 10 。

对于 20% 的数据,保证 n ≤ 10;

对于 100% 的数据,保证 n ≤ 1000; wi ≤ 20; vi ≤ 20000 。

印象中第一次做这一类的题,这个应该也是个蛮典的题,本人dp比较烂,做题过程中也算对01背包等一类背包问题有了一些新的感悟,先说感悟再说解法

拿01背包来说,01背包实际有一个隐含条件,对于dpij和dpkj,i小于k,选择i后面可能可以选择k,选择k后面必然不能选择i,在实际场景中如果两者没有实际的制约与时序关系,那么我们就需要构造一个时序,在最基本01背包中,看起来i和k没有什么制约关系,但实际我们设置状态转移方程时也假设了i只会出现在k之前而不会出现在k后面的条件。说的不太清楚,凑合看看吧。

拿这个题来说

对于每个砖块怎么保证,他上面的重量总和小于等于他的价值呢,这个该怎么维护呢。实际上在纸上画一画,思考一下可以先处理上面的砖块,再处理下面的砖块,一点一点的处理,因为你如果先处理下面的砖块,你怎么选对吧,才能保证下面的都满足。所以先考虑上面的,从上往下每个砖块都能线性处理。

定义dp[i] [j]是用了前i个砖块,此时重量恰好为j的时候的最大价值。

但是这样该怎么枚举砖块的顺序呢?实际上这就是要排序,以前就做过这种,比如国王的游戏。这题可以让i在上面,j在下面,我们让wi+sum<vj,wj+sum>vi,也就是让i在上面的时候j可以选,让i在下面的时候,j不可以选了。所以转化一下这个公式,可以把sum丢掉,sum是上面所有的重量。然后公式就是wi<vj,vi<wj。两个想加可以得到wi+vi<wj+vj。所以按这个排序就行。然后对于维护每个砖块上面的重量小于他的价值,其实在dp的时候加个判断条件就够了。然后其实就是01背包,加了一个贪心排序,和多了一个判断条件。可以优化为1维的。

没有写滚动数组版本的,大家自己写写吧

#include <iostream>
#include<vector>
#include<map>
#include<string>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll N = 1e5 + 10;
const ll mod = 1e9 + 7;
struct node {
	int w, v;
	bool operator<(const node& a) {
		return w + v < a.w + a.v;
	}
}p[1010];
int dp[1010][20010];
void solve()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> p[i].w >> p[i].v;
	int ans = 0;
	sort(p + 1, p + 1 + n);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n * 20 && j - p[i].w <= p[i].v; j++) {
			dp[i][j] = dp[i - 1][j];
			if (j - p[i].w >= 0) {
				if (dp[i - 1][j - p[i].w] != 0)
					dp[i][j] = max(dp[i][j], dp[i - 1][j - p[i].w] + p[i].v);
				if (j - p[i].w == 0)
					dp[i][j] = max(p[i].v, dp[i][j]);
			}
			ans = max(dp[i][j], ans);
		}
	cout << ans << '\n';
}

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


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

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

相关文章

硬件测试—温升测试之JinKo 多路温度测试仪使用说明

一、概述 1.1&#xff1a;测试概述 在硬件测试中&#xff0c;温升测试也是很重要的一项测试&#xff0c;产品各项器件在稳定的环境温度下满载工作的芯片温度&#xff0c;根据测试情况评估散热需求。 1.2&#xff1a;产品图片 1.3&#xff1a;使用设备 名称 厂家 型号 PC电脑…

Acer Aspire V3-572G电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件配置 硬件型号驱动情况 主板Acer Aspire V3-572G 处理器i7 5500U 2 Cores/4 Threads2,4Ghz已驱动 内存Any Samsung, Hynix or Kingston DDR3 8GB(4GBx2).已驱动 硬…

CSDN 每日一练用例数据缺失了怎么办?

CSDN 每日一练用例数据缺失了怎么办&#xff1f; 引子1、用例与结果不匹配2、阅读理解困难3、用例数据缺失 用例数据缺失&#xff0c;却有人 AC &#xff1f;神奇的 c28761 津津的储蓄计划70093 近视的小张 小结最后的吐槽 引子 老顾最近几个月经常在 CSDN 举办的周赛上浑水摸…

Tomcat 部署

一.Tomcat介绍 Servlet 是 Java Servlet 的简称&#xff0c;可以理解为是一个服务连接器&#xff0c;是用 Java 编写的服务器端程序&#xff0c;具有独立于平台和协议的特性&#xff0c; 简单的理解&#xff1a;servlet 就是一个中间件&#xff0c;包含了接口和方法&#xff0…

5.2.6 地址解析协议ARP

5.2.6 地址解析协议ARP 我们知道要想实现全球范围内主机之间的通信&#xff0c;必须要有两个统一&#xff0c;一个是地址&#xff0c;另一个是数据格式&#xff0c;我们使用IP地址来实现统一的地址&#xff0c;使用IP分组实现统一的数据格式&#xff0c;在前面局域网的学习中我…

【AIGC】13、GLIP | 首次将 object detection 重建为 phrase grounding 任务

文章目录 一、背景二、方法2.1 将 object detection 和 phrase grounding 进行统一2.2 Language-aware deep fusion2.3 使用语义丰富的数据来进行预训练 三、效果3.1 迁移到现有 Benchmarks3.2 在 COCO 上进行零样本和有监督的迁移3.3 在 LVIS 上进行零样本迁移学习3.4 在 Flic…

android 如何分析应用的内存(四)

android 如何分析应用的内存&#xff08;四&#xff09; 接上文 在介绍细节部分时&#xff0c;先介绍了各种工具的使用&#xff0c;而这些工具&#xff0c;大部分都用来调试&#xff0c;诸如&#xff1a;特定内存点&#xff0c;堆栈&#xff0c;寄存器&#xff0c;变量值等的…

MySQL安装流程 及 8.0与5.7区别

一、MySQL版本介绍 1、MySQL 8.0 窗口函数&#xff1a;MySQL 8.0版本支持窗口函数&#xff0c;这是数据分析工作中非常常用的一类函数。窗口函数可以让用户在单个查询中跨多个行检索数据&#xff0c;并在查询结果中对数据执行计算。隐藏索引&#xff1a;在MySQL 8.0版本中&am…

C++STL详解 string【C++】

文章目录 函数模板函数模板的原理函数模板的实例化模板参数的匹配原则 类模板类模板的定义格式类模板的实例化 string 函数模板 函数模板的原理 template <typename T> //模板参数 ——类型 void Swap(T& x1, T& x2) {T tmp x1;x1 x2;x2 tmp; } int main()…

牛客网语法刷题篇(C语言) — 输出格式化

&#x1f929;本文作者&#xff1a;大家好&#xff0c;我是paperjie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 &#x1f970;内容专栏&#xff1a;这里是《C语言—语法篇》专栏&#xff0c;笔者用重金(时间和精力)打造&#xff0c;基础知识一网打尽&#xff0c;…

解析Linux中断子系统之中断映射

中断是当前计算机系统的基础功能&#xff0c;也是系统响应外设事件的必备桥梁。不同的架构对中断控制器有不同的设计理念&#xff0c;本文针对ARM公司提供的通用中断控制器&#xff08;GIC,Generic Interrupt Controller&#xff09;介绍在linux系统中的硬件中断号与软件中断号…

SpringBootWeb登录认证

1. 登录功能 1.1 需求 在登录界面中&#xff0c;我们可以输入用户的用户名以及密码&#xff0c;然后点击 “登录” 按钮就要请求服务器&#xff0c;服务端判断用户输入的用户名或者密码是否正确。如果正确&#xff0c;则返回成功结果&#xff0c;前端跳转至系统首页面。 1.2 …

简单聊一聊数据库驱动

数据库驱动通常是数据库厂家提供的&#xff0c;他们按照jdbc协议对自家数据库封装了一套可对外调用的API。在应用程序和数据库之间起到了桥接的作用。它是一个软件组件&#xff0c;提供了与特定数据库系统进行通信的接口和功能。 1. 数据库驱动的作用&#xff1a; 连接数据库&…

AAOS 音频动态路由

文章目录 基本概念车载音频配置文件外部的配置音频区的方式车载音频服务配置路由流程框架中获取可用输出设备配置例子测试方法相关问题 基本概念 Android 管理来自 Android 应用的声音&#xff0c;同时控制这些应用&#xff0c;并根据其声音类型将声音路由到 HAL 中的输出设备…

FastAPi上传文件报错,There was an error parsing the body

问题描述 通过postman调用fastapi编写的文件接口报错&#xff0c;如下图&#xff1a; {"detail": "There was an error parsing the body" } 问题的解决过程 postman本身的问题 postman有个work directory的概念&#xff0c;所以再使用postman上传的文…

Git常用命令submodule

Git常用命令submodule 1、需求 当程序比较大参与开发人员较多时&#xff0c;代码管理就复杂起来。代码如果全员可见&#xff0c;可以创建 share 分支维护共用代 码&#xff0c;可以创建 core 分支维护核心算法代码&#xff0c;各进程分别占一个分支&#xff0c;定期同步 sha…

如何从 OpenAI 迁移到 Azure OpenAI(保姆级教程,包含如何兼容 JS 语言版 LangChain)

Azure OpenAI 和 OpenAI 一样&#xff0c;本质都是调用 api&#xff0c;Azure OpenAI 的使用会稍微复杂一点&#xff0c;但好处就是方便付费。 创建 Azure OpenAI 资源 首先&#xff0c;先登录 Azure 账号&#xff1a;https://azure.microsoft.com/zh-cn/ 接着创建 OpenAI 资…

硬件工程师-BOOST升压电源设计

一、Boost变换原理 开关闭合时&#xff0c;电感电压等于输入电压 开关断开时&#xff0c;电感电压输出电压-输入电压&#xff0c; 电感的感生电动势&#xff0c;N ΔΦ磁通的变化率&#xff0c;Δt时间 假设开关闭合与开关断开&#xff0c;开关断开时能量全部释放光 将第三个式…

MySQL(进阶篇1.0)

MySQL体系结构 1、连接层 最上层是一些客户端和连接服务&#xff0c;包含本地sock通信和大多数基于客户端/服务端工具实现的类似于TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关安全方案。在该层上引入了线程池的概念&#xff0c;为通过认证安全接入的客户端提…

进程的通信方式有哪些?

目录 管道消息队列共享内存信号量信号套接字 管道 最初我们在学习Linux基本命令使用的时候&#xff0c;我们经常通过多个命令的组合来完成我们的需求。比如说我们想知道如何查看进程或者端口是否在使用&#xff0c;会使用下面的这条命令 netstat nlp | grep xxx 这里的"|“…