牛客练习赛123(A,B,C,D)

牛客挑战赛,练习赛和小白月赛周赛不是一种东西。这玩意跟CF的div12差不多难度。而且找不到题解。所以决定不等题解补题了,直接写题解了。

比赛链接

光速签到下班,rk++。感觉E可能能补掉,看情况补吧。

B题感觉之前考了两次,结论和证明构造过程需要理解,赛时记得结论直接秒了。C题是不太裸的裸完全背包,思路不裸但是写法裸。D题需要加个优化,思路看的别人的,很妙。


A 炸鸡块哥哥的粉丝题

思路:

签到,截取前一半的子串即可。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int n;
string s;

int main(){
	cin>>n>>s;
	cout<<s.substr(0,(n+1)/2);
	return 0;
}

B 智乃想考一道鸽巢原理

思路:

看了评论区题解才发现,自己这么长时间理解的方法原来就是鸽巢原理。指路

我们想让某一种小球留下来,肯定先让其他小球先配对抵消掉,其他小球抵消剩下的再用这种小球来消。那么问题就变成了求其他小球抵消剩下的小球有几个,如果剩下的球比这种小球少,那就可以剩下这种小球,否则就剩不下。

我们把最多的那个小球看作是鸽巢,然后剩余的小球看作是鸽子,也就是鸽巢有 m x mx mx 个,鸽子有 r m = t o t − a i rm=tot-a_i rm=totai 个。

  1. m x > ⌊ r m 2 ⌋ mx\gt \left\lfloor\dfrac{rm}2\right\rfloor mx>2rm 时:可以每个鸽巢放入一只鸽子,此时剩余的小球个数就是剩余的鸽巢个数,即 m x − ( r m − m x ) = 2 ∗ m x − r m mx-(rm-mx)=2*mx-rm mx(rmmx)=2mxrm
  2. m x ≤ ⌊ r m 2 ⌋ mx\le \left\lfloor\dfrac{rm}2\right\rfloor mx2rm 时:可以用其他小球来充当鸽巢,使得鸽巢拓展到 ⌈ r m 2 ⌉ \left\lceil\dfrac{rm}2\right\rceil 2rm 个。然后其他小球依次放入鸽巢即可,可以保证存在一种方法使得小球不会放在同种颜色小球的鸽巢里(因为最少可以只有一种颜色又当鸽巢又放小球,其他颜色就不可能重复了。而每种颜色小球个数不会超过 ⌈ r m 2 ⌉ \left\lceil\dfrac{rm}2\right\rceil 2rm 个,所以这种颜色可以不重复)。此时会剩余 r m % 2 rm\%2 rm%2 个鸽巢。

所以我们枚举 i i i 时,对每个 i i i 只要知道剩余的小球的总个数和剩余最大个数的小球,就可以计算其他小球抵消最后会剩多少小球,也就知道能否剩下这种小球。我们可以设置一个变量记录所有小球个总个数,并处理出前缀最大值和后缀最大值,这样就可以快速查询了。

code:

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;

int T,n;
int a[maxn],prem[maxn],sufm[maxn];
ll tot;

int main(){
	cin>>T;
	while(T--){
		cin>>n;
		tot=0;
		for(int i=1;i<=n+1;i++)prem[i]=sufm[i]=0;
		for(int i=1;i<=n;i++){
			cin>>a[i];
			prem[i]=max(prem[i-1],a[i]);
			tot+=a[i];
		}
		for(int i=n;i>=1;i--)sufm[i]=max(sufm[i+1],a[i]);
		
		for(int i=1;i<=n;i++){
			ll mx=max(prem[i-1],sufm[i+1]),rm=tot-a[i],lst;
			if(mx>rm/2)lst=2*mx-rm;
			else lst=rm&1;
			cout<<"01"[a[i]>lst]<<" \n"[i==n];
		}
	}
	return 0;
}

C 智乃想考一道完全背包(Easy version)

思路:

如果位置 k k k 上的物品本来就很好了,那么肯定选这个物品就行了。但是如果有个很好的物品远离位置 k k k,那么我们就需要选上从这个位置到 k k k 上的所有物品,才能选上这一个物品,它就相当于和中间的物品进行捆绑销售了。

反正一定会捆绑销售,所以我们不如一开始就将 l ∼ k l\sim k lk k ∼ r k\sim r kr 位置上的物品进行绑定,把它们变成一个物品,然后跑完全背包。

不过由于我们选了 l ∼ k l\sim k lk 的物品的话,我们还能去拓展另一边到 r r r,并省下一个 k k k。所以另一边我们也需要绑定过来,也就是说需要把 l ∼ r l\sim r lr 上的物品进行绑定。

如果我们以位置为横坐标,每个位置上物品选择的个数为纵坐标画直方图的话,它的形状就是一个金字塔型。我们绑定物品同时选取,其实就相当于绑定一行,每行都是整块选取。

时间复杂度看似是 O ( n 2 ∗ m ) O(n^2*m) O(n2m) 的。但是由于背包容量最多 m m m,重量超过 m m m 的物品我们根本更新不了答案,所以最多有 m 2 m^2 m2 级别个物品会更新 d p dp dp 值,所以时间复杂度最多是 O ( n 2 + m 3 ) O(n^2+m^3) O(n2+m3) 的。

code:

没必要开longlong

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=2005;
const int maxm=505;
typedef long long ll;
const ll linf=1e18;

int n,m,k;
ll dp[maxm];

ll tw[maxn],tv[maxn];

int main(){
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++){
		cin>>tw[i]>>tv[i];
		tw[i]+=tw[i-1];
		tv[i]+=tv[i-1];
	}
	for(int l=1;l<=k;l++)
		for(int r=k;r<=n;r++){
			ll w=tw[r]-tw[l-1],v=tv[r]-tv[l-1];
			for(int j=w;j<=m;j++)
				dp[j]=max(dp[j],dp[j-w]+v);
		}
	
	for(int i=1;i<=m;i++){
		dp[i]=max(dp[i-1],dp[i]);
		cout<<dp[i]<<" ";
	}
	return 0;
}

D 智乃想考一道完全背包(Hard version)

思路:

朴素的想法是设 d p [ k ] [ j ] dp[k][j] dp[k][j] 表示位置 k k k 为中心,容量为 j j j 的最大价值。直接枚举 k k k 的位置,对每个位置做法和上面相同,这样时间复杂度就会变成 O ( n ∗ m 3 ) O(n*m^3) O(nm3),会 T T T 1 3 \frac13 31 的点。

考虑优化,发现对于选取了区间 l ∼ r l\sim r lr 的整块物品,它可以去更新 k ∈ [ l , r ] k\in[l,r] k[l,r] 的所有位置,而没有必要在选取不同 k k k 的时候分别去更新每个 d p [ k ] [ − ] dp[k][-] dp[k][]

原本我们先从小到大枚举 l l l,固定好 l l l 后,然后枚举 r r r k k k,对一个位置 k k k,它应该用 [ l , r = k ∼ n ] [l,r=k\sim n] [l,r=kn] 的物品来更新。这里为了实现上面说的优化,我们从大到小枚举 r r r,并且令 k = r k=r k=r,这样算出来的 d p [ r ] [ − ] dp[r][-] dp[r][] 就考虑到了 [ l , r = k ∼ n ] [l,r=k\sim n] [l,r=kn] 所有物品。 d p [ r ] [ − ] dp[r][-] dp[r][] 直接从 d p [ r + 1 ] [ − ] dp[r+1][-] dp[r+1][] 转移过来或者从 [ l , r ] [l,r] [l,r] 这件物品转移过来即可

这样优化后,由于不需要枚举 k k k 的位置,时间复杂度被优化成了 O ( m 3 ) O(m^3) O(m3)。可以通过。

code:

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=2005;
const int maxm=505;
typedef long long ll;
const ll linf=1e18;

int n,m;
ll dp[maxn][maxm];
//位置为k,背包容量为j 

ll tw[maxn],tv[maxn];
int ans[maxn],id[maxn];

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>tw[i]>>tv[i];
		tw[i]+=tw[i-1];
		tv[i]+=tv[i-1];
	}
	
	for(int l=1;l<=n;l++){
		ll w,v;
		for(int r=n;r>=l;r--){
			w=tw[r]-tw[l-1];
			v=tv[r]-tv[l-1];
			for(int j=w;j<=m;j++)
				dp[r][j]=max(dp[r][j],max(dp[r+1][j],dp[r][j-w]+v));
		}
	}

	
	for(int i=1;i<=m;i++){
		ll maxx=-linf,idx;
		for(int k=1;k<=n;k++){
			dp[k][i]=max(dp[k][i-1],dp[k][i]);
			if(dp[k][i]>maxx){
				maxx=dp[k][i];
				idx=k;
			}
		}
		ans[i]=maxx;
		id[i]=idx;
	}
	for(int i=1;i<=m;i++)cout<<ans[i]<<" \n"[i==m];
	for(int i=1;i<=m;i++)cout<<id[i]<<" \n"[i==m];
	return 0;
}

相关推荐

  1. 练习123(A,B,C,D)

    2024-03-30 20:36:03       17 阅读
  2. 练习50-C

    2024-03-30 20:36:03       39 阅读
  3. 26

    2024-03-30 20:36:03       34 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-30 20:36:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-30 20:36:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-30 20:36:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-30 20:36:03       18 阅读

热门阅读

  1. 智能电销机器人的功能体现

    2024-03-30 20:36:03       19 阅读
  2. 机器学习实验------AGNES层次聚类方法

    2024-03-30 20:36:03       17 阅读
  3. react中moment方法

    2024-03-30 20:36:03       16 阅读
  4. YOLO图像前处理及格式转换

    2024-03-30 20:36:03       21 阅读
  5. 计算机OSI7层协议模型

    2024-03-30 20:36:03       16 阅读
  6. 用CSS实现单行、多行文本溢出隐藏

    2024-03-30 20:36:03       17 阅读
  7. Leetcode 674. 最长连续递增序列

    2024-03-30 20:36:03       16 阅读
  8. 搜索框中文输入导致高频触发的优化

    2024-03-30 20:36:03       17 阅读
  9. 设计模式(4):建造者模式

    2024-03-30 20:36:03       18 阅读
  10. 第二十二篇-ZincSearch-安装部署

    2024-03-30 20:36:03       15 阅读