牛客周赛 Round 39(A,B,C,D,E,F,G)

news2024/11/27 21:43:29

比赛链接

官方题解(视频)

B题是个贪心。CD用同余最短路,预处理的完全背包,多重背包都能做,比较典型。E是个诈骗,暴力就完事了。F是个线段树。G是个分类大讨论,出题人钦定的本年度最佳最粪 题目


A 小红不想做炸鸡块粉丝粉丝题

思路:

签到

code:

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

int a,tot;

int main(){
	cin>>a;
	tot=a;
	for(int i=2,t;i<=6;i++)
		cin>>t,tot+=t;
	if(a*30>=tot)puts("No");
	else puts("Yes");
	return 0;
}

B 小红不想做鸽巢原理

思路:

emmmm不太清楚和鸽巢原理有啥关系,就是个贪心的思路。

因为是 k k k k k k 个取走,所以假设一共有 t o t tot tot 个小球,最后会剩下 t o t % k tot\%k tot%k 个小球。因为要剩下的种类尽可能少,那么我们尽可能留下数量多的种类就行了。

code:

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

int n,k;
ll tot=0;
set<int> S;

int main(){
	cin>>n>>k;
	for(int i=1,t;i<=n;i++){
		cin>>t;
		S.insert(t);
		tot+=t;
	}
	tot%=k;
	if(tot==0){
		cout<<0<<endl;
		return 0;
	}
	int ans=0;
	for(auto it=S.rbegin();it!=S.rend();it++){
		ans++;
		if(tot>*it)tot-=*it;
		else break;
	}
	cout<<ans<<endl;
	return 0;
}

C,D 小红不想做完全背包

思路:

和寒假营第二场的D题是同种类型的题,做法有三:同余最短路,带预处理的完全背包,多重背包。

因为我们只想要是 p p p 的倍数,而这个数是什么我们不关心,所以我们用到的数都直接模 p p p 即可,当模 p p p 等于零的时候就是 p p p 的倍数了,这就算是比较典型板子 的带同余的完全背包问题了。

它和一般的完全背包还不太一样,普通的完全背包跑一趟就够了,因为重量不会无缘无故减少,我们只要从小到大跑一遍就能考虑到所有情况了,但是带同余的话重量就有可能减少了。比如容量为 7 7 7,物品的重量为 3 3 3,不带只跑一遍和带了跑到重复为止的结果是不一样的,如下图:

容量:0 1 2 3 4 5 6

不带:0 0 1 0 0 2 0
带了:5 3 1 6 4 2 7

一般来说,我们从某个位置出发,为了跑到第一次重复,至少需要跑 p 2 g c d ( a i , p ) \dfrac {p^2}{gcd(a_i,p)} gcd(ai,p)p2 次(设 a i ∗ x ≡ a i ( m o d p ) a_i*x\equiv a_i\pmod p aixai(modp),解出来 x = p g c d ( a i , p ) + 1 x=\dfrac p{gcd(a_i,p)}+1 x=gcd(ai,p)p+1,也就是说一趟只用跑 p g c d ( a i , p ) \dfrac p{gcd(a_i,p)} gcd(ai,p)p 次就可以停了,再以每位置开始跑一趟,一共 p ∗ p g c d ( a i , p ) p*\dfrac p{gcd(a_i,p)} pgcd(ai,p)p 次)。再算上有 n n n 件物品,这样时间复杂度就爆了, 最坏情况 O ( n ∗ p 2 ) O(n*p^2) O(np2)

大致代码如下,TLE了(数据太弱了,居然就T了三个点,而且如果就算不枚举开始位置,只跑一次,甚至只WA三个点,经过某些神秘的顺序安排,居然还能AC,给人一种做法是正确的的错觉)

	cin>>n>>p;
	vector<int> a(n);
	for(int i=0,t;i<n;i++){
		cin>>t;
		a[i]=t%p;
	}
	sort(a.begin(),a.end());
	a.erase(unique(a.begin(),a.end()),a.end());
	n=a.size();
	vector<int> dp(p+5,1e9);
	
	for(auto x:a){
		dp[x]=1;
		for(int idx=0;idx<p;idx++)
			for(int i=1,t=(idx+x)%p;i<p/gcd(x,p);i++,t=(t+x)%p)
				dp[(t+x)%p]=min(dp[(t+x)%p],dp[t]+1);
	}
	cout<<dp[0];

发现我们没必要从每个位置开始都跑 p g c d ( a i , p ) \dfrac p{gcd(a_i,p)} gcd(ai,p)p 次,我们用多个物品得到的重量是固定的,我们不如一开始就处理好,然后直接拿来用。具体来说,设 c s t [ i ] cst[i] cst[i] 表示增加重量为 i i i 需要使用多少个物品,多个物品可以都处理到一个 c s t [ i ] cst[i] cst[i],预处理的时间复杂度为 n ∗ p g c d ( a i , p ) n*\dfrac p{gcd(a_i,p)} ngcd(ai,p)p,使用的时候直接把 c s t [ i ] cst[i] cst[i] 当作物品跑完全背包,每个物品只跑一趟即可。

为什么预处理后不需要跑多趟了?原来我们用物品 a i a_i ai 跑第一次的时候,这时相当于用 c s t [ a i % p ] cst[a_i\%p] cst[ai%p] 跑一次,原来我们用物品 a i a_i ai 跑第二次的时候,这时相当于用 c s t [ 2 ∗ a i % p ] cst[2*a_i\%p] cst[2ai%p] 跑一次,原来我们用物品 a i a_i ai 跑第三次的时候,这时相当于用 c s t [ 3 ∗ a i % p ] cst[3*a_i\%p] cst[3ai%p] 跑一次,类推,甚至我们多个物品同时处理后,这个 c s t cst cst 值还会更小,答案更优。因此我们原本每个位置每个物品跑多次,现在只要每个位置每个 c s t cst cst 跑一次就可以了。

因此完全背包部分时间复杂度就优化为了 O ( p 2 ) O(p^2) O(p2)。总的时间复杂度就优化为了 O ( n ∗ p g c d ( a i , p ) + p 2 ) O(\dfrac {n*p}{gcd(a_i,p)}+p^2) O(gcd(ai,p)np+p2),最坏 O ( n p + p 2 ) O(np+p^2) O(np+p2)

另外同余最短路和多重背包也是正确的做法,数据弱,奇奇怪怪的做法也能日过去。

code:

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=2005;

int n,p;
int gcd(int a,int b){
	while(b)b^=a^=b^=a%=b;
	return a;
}

int main(){
	cin>>n>>p;
	vector<int> a(n);
	for(int i=0,t;i<n;i++){
		cin>>t;
		a[i]=t%p;
	}
	sort(a.begin(),a.end());
	a.erase(unique(a.begin(),a.end()),a.end());
	n=a.size();
	vector<int> cst(p+5,1e9),dp(p+5,1e9);
	for(auto x:a){
		for(int i=1,cur=x;i<=p;i++,cur=(cur+x)%p){
			cst[cur]=min(cst[cur],i);
		}
	}
	
	for(int i=0;i<p;i++){
		int x=cst[i];//i步数 x代价 
		dp[i]=min(dp[i],x);
		for(int j=i;j<p+i;j++)
			dp[j%p]=min(dp[j%p],dp[(j-i+p)%p]+x);
	}
	cout<<dp[0];
	return 0;
}

E 小红不想做莫比乌斯反演杜教筛求因子和的前缀和

思路:

之前练习赛出了一个名字差不多的题,特难。这次出题人估计是想骗做题人给自己上压力,不过可惜放在了 E E E 题的位置上。没骗到。

枚举长 n n n 和宽 m m m,然后算出 p p p,统计答案个数即可。

code:

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

int n,m,p,x;
int ans=0;

int main(){
	cin>>n>>m>>p>>x;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if((x-i*j)%(2*(i+j))==0 && (x-i*j)/(2*(i+j))>=1 && (x-i*j)/(2*(i+j))<=p)
				ans++;
	cout<<ans;
	return 0;
}

F 小红不想做模拟题

思路:

区间修改,区间查询,还是比较明显能想到线段树的。

当我们区间推平时,比如推平了 a a a 串的区间 [ l , r ] [l,r] [l,r],把它变成 1 1 1,那么这一段区间 1 1 1 的对数就变成了 b b b 串这段区间中 1 1 1 的个数,同理推平另一个串。所以我们为了维护区间 1 1 1 的对数,还需要分别维护住 a , b a,b a,b 串区间内 1 1 1 的个数。

另外因为这个题只进行了一个简单的推平操作,所以我们也不需要写懒节点并将节点信息向下传递,我们只要在线段树节点上打个标记,表示是否推平了,之后修改或者查询的时候查到标记就直接返回就行了。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=1e5+5;

int n,q;
string str[2];

struct segment_tree{
	#define ls p<<1
	#define rs p<<1|1
	
	struct Node{
		int l,r;
		int a,b;//区间内 a串1的个数,b串1的个数
		int sam;//ab串同为1的位置的个数
		bool fa,fb;//是否填平
		Node(int l=0,int r=0,int a=0,int b=0,int sam=0,bool fa=false,bool fb=false):l(l),r(r),a(a),b(b),sam(sam),fa(fa),fb(fb){}; 
	}tr[maxn<<4];
	
	void push_up(int p){
		auto& [l,r,a,b,sam,fa,fb]=tr[p];
		
		a=(fa)?r-l+1:tr[ls].a+tr[rs].a;
		b=(fb)?r-l+1:tr[ls].b+tr[rs].b;
		
		if(fa)sam=tr[p].b;
		else if(fb)sam=tr[p].a;
		else sam=tr[ls].sam+tr[rs].sam;
	}
	void build(int p,int l,int r){
		tr[p].l=l;
		tr[p].r=r;
		if(l==r){
			tr[p].a=(str[0][l-1]=='1');
			tr[p].b=(str[1][l-1]=='1');
			tr[p].sam=(tr[p].a && tr[p].b);
			return;
		}
		int mid=l+r>>1;
		build(ls,l,mid);
		build(rs,mid+1,r);
		push_up(p);
	}
	void print(int p,int l,int r){
		printf("%d [%d,%d]:%d %d %d\n",p,l,r,tr[p].a,tr[p].b,tr[p].sam);
		if(l==r){
			return;
		}
		int mid=l+r>>1;
		print(ls,l,mid);
		print(rs,mid+1,r);
	}
	void print(){print(1,1,n);}
	
	void modify(int p,int l,int r,int L,int R,bool st){
		if(L<=l && r<=R){
			if(st){//填平a串 
				tr[p].a=r-l+1;
				tr[p].fa=true;
				tr[p].sam=tr[p].b;
			}
			else {//填平b串 
				tr[p].b=r-l+1;
				tr[p].fb=true;
				tr[p].sam=tr[p].a;
			}
			return;
		}
		int mid=l+r>>1;
		if(mid>=L)modify(ls,l,mid,L,R,st);
		if(mid<R)modify(rs,mid+1,r,L,R,st);
		push_up(p);
	}
	int q(){return tr[1].sam;}
	
	#undef ls
	#undef rs
}tr;

int main(){
//	cin.tie(0)->sync_with_stdio(false);
	
	cin>>n>>str[0]>>str[1];
	tr.build(1,1,n);
	for(cin>>q;q;q--){
		char ch;
		int l,r;
		cin>>ch>>l>>r;
		tr.modify(1,1,n,l,r,(ch=='A'));
		cout<<tr.q()<<endl;
//		tr.print();
//		cout<<endl;
	}
	return 0;
}

G 小红不想做平衡树

思路:

我们发现,在一个数列里,数列一定是升序段降序段交替出现的,比如:升序-降序-升序-降序…,或者 降序-升序-降序-升序…。

我们选择一段区间,然后翻转其某个子段,使得反转后成为一个升序序列,有五种可能的情况(因为题目保证了数列中数各不相同,所以这里不讨论数值相等的情况,下面默认如此):

  1. 整段升序。
  2. 整段降序。
  3. 先升序,后降序。而且第一段最大值小于第二段最小值。
  4. 先降序,后升序。而且第一段最大值小于第二段最小值。
  5. 先升序,后降序,再升序。第一段最大值小于第二段最小值,且第二段最大值小于第三段最小值。

大概示例图如下:
在这里插入图片描述

我们对每种情况分别讨论,然后统计答案即可。

不过实际在写的时候会非常麻烦,因为前一段的末尾那个数正好就是后一段开头的那个数,导致上面的五种情况会出现重叠计数的情况。比如第三种情况中,第二段只取第一个数时,统计出来的答案就会和第一种情况完全重复,再比如第五种情况中第一段只选第一个数时统计出来的答案都和第四种情况出现重复等。在官方题解的写法中,细节也是蛮多的。下面只讲我的写法,和题解不太一样。

回到开头,在一个数列里,数列一定是升序段降序段交替出现的,而升序段和降序段交界处的那个数是两段共用的。这种“转折点”有两种类型:升序变降序(形如 ^),降序变升序(形如 √)。而且是交替出现的。

我们可以把这些转折点处理出来,然后根据转折点来统计答案。虽然仍然会出现重复的情况,但是更直观一些(大概?)

code:

#include <iostream>
#include <cstdio>
#include <vector>
#define pii pair<int,int>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;

int n,a[maxn];

int main(){
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	
	ll ans=0;
	int st=-1;//第一个 ^ 点的位置
	vector<int> ver;
	for(int i=2,f;i<n;i++){
		f=-1;
		if(a[i-1]<a[i] && a[i]>a[i+1])f=0;// ^
		if(a[i-1]>a[i] && a[i]<a[i+1])f=1;// √
		if(!~st)st=f;
		if(~f)ver.push_back(i);
	}
	int tl=1,len,tn=ver.size();//1 2
	for(auto i:ver){
		len=i-tl+1;
		ans+=1ll*(len+1)*len/2;
		tl=i;
	}
	len=n-tl+1;
	ans+=1ll*(len+1)*len/2;
	ans-=tn;
	
	for(int i=st,id,l,r;i<ver.size();i+=2){//3
		id=ver[i];
		l=(i==0)?1:ver[i-1];
		r=(i==ver.size()-1)?n:ver[i+1];
		
		for(int j=id+1;j<=r;j++){//这边从id+1的位置开始统计,当j=id时会和情况2重复
			if(a[j]>a[id-1])ans+=id-l;
			else break;
		}
	}
	for(int i=st^1,id,l,r;i<ver.size();i+=2){//4
		id=ver[i];
		l=(i==0)?1:ver[i-1];
		r=(i==ver.size()-1)?n:ver[i+1];
		
		for(int j=id-1;j>=l;j--){//这边从id-1的位置开始统计,当j=id时会和情况1重复
			if(a[j]<a[id+1])ans+=r-id;
			else break;
		}
	}
	for(int i=st,id1,id2,l,r;i+1<ver.size();i+=2){//5
		id1=ver[i];
		id2=ver[i+1];
		l=(i==0)?1:ver[i-1];
		r=(i+1==ver.size()-1)?n:ver[i+2];
		
		if(a[id1-1]<a[id2] && a[id1]<a[id2+1])ans+=1ll*(id1-l)*(r-id2);
	}
	
	cout<<ans<<endl;
	
	return 0;
}

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

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

相关文章

Unity之PUN实现多人联机射击游戏的优化(Section 3)

目录 &#x1f4a3;一、准备工作 &#x1f4a3;二、生成弹头脚本的编写 &#x1f4a3;三、实现发射和伤害同步 手雷都加了在给狗剩加个火箭筒不过分吧。效果看GIF动图&#xff0c;分别是单机和联机的效果。 添加火箭筒依旧是在原有的基础上更改&#xff0c;我查看火箭筒模型…

性能测试-数据库优化二(SQL的优化、数据库拆表、分表分区,读写分离、redis)

数据库优化 explain select 重点&#xff1a; type类型&#xff0c;rows行数&#xff0c;extra SQL的优化 在写on语句时&#xff0c;将数据量小的表放左边&#xff0c;大表写右边where后面的条件尽可能用索引字段&#xff0c;复合索引时&#xff0c;最好按复合索引顺序写wh…

如何解决Uniapp更新数据不重新渲染组件

办法就是在修改数据的函数里面&#xff0c;用let thatthis&#xff0c;再给that用赋值。 原因是给数据赋值的函数没用箭头函数&#xff0c;this是函数自己的this。比如success&#xff08;res&#xff09;{} 或者用箭头函数&#xff0c;比如success&#xff08;res&#xff0…

2024年mathorcup数学建模C题思路分析-物流网络分拣中心货量预测及人员排班

# 1 赛题 C 题 物流网络分拣中心货量预测及人员排班 电商物流网络在订单履约中由多个环节组成&#xff0c;图 ’ 是一个简化的物流 网络示意图。其中&#xff0c;分拣中心作为网络的中间环节&#xff0c;需要将包裹按照不同 流向进行分拣并发往下一个场地&#xff0c;最终使包裹…

数学杂谈之四:学习数学的方法

数学杂谈之四&#xff1a;学习数学的方法 数学杂谈之一&#xff1a;数学的形态 https://blog.csdn.net/cnds123/article/details/137437208 数学杂谈之二&#xff1a;数学中的概念和理解 https://blog.csdn.net/cnds123/article/details/137500537 数学杂谈之三&#xff1a;…

【MVCC】深入浅出彻底理解MVCC

MVCC概述 MVCC&#xff08;Multi-Version Concurrency Control&#xff09;即多版本并发控制。主要是为了提高数据库的并发性能而提供的&#xff0c;采用了不加锁的方式处理读-写并发冲突&#xff0c;确保了任何时刻的读操作都是非阻塞的。只需要很小的开销&#xff0c;就可以…

机器学习和深度学习 -- 李宏毅(笔记与个人理解)Day 13

Day13 Error surface is rugged…… Tips for training :Adaptive Learning Rate critical point is not the difficult Root mean Square --used in Adagrad 这里为啥是前面的g的和而不是直接只除以当前呢? 这种方法的目的是防止学习率在训练过程中快速衰减。如果只用当前的…

文心一言

文章目录 前言一、首页二、使用总结 前言 今天给大家带来百度的文心一言,它基于百度的文心大模型,是一种全新的生成式人工智能工具。 一、首页 首先要登录才能使用,左侧可以看到以前的聊天历史 3.5的目前免费用,但是4.0的就需要vip了 二、使用 首先在最下方文本框输入你想要搜…

PostgreSQL15 + PostGis + QGIS安装教程

目录 下载1、PostgreSQL安装1.1、环境变量配置 2、PostGIS安装2.1、安装插件 3、QGIS下载3.1、安装3.2、测试 下载 PostgreSQL15安装&#xff1a;下载地址 PostGIS安装&#xff1a;下载地址&#xff08;倒数第二个&#xff09; 1、PostgreSQL安装 下载安装包之后一直点下一步…

Redis从入门到精通(十五)Redis分布式缓存(三)Redis分片集群的搭建和原理分析

文章目录 前言5.4 分片集群5.4.1 搭建分片集群5.4.2 散列插槽5.4.3 集群伸缩5.4.3.1 需求分析5.4.3.2 创建新的Redis实例5.4.3.3 添加新节点到Redis集群5.4.3.4 转移插槽 5.4.4 故障转移5.4.4.1 自动故障转移5.4.4.2 手动故障转移 5.4.5 RedisTemplate 5.5 小结 前言 Redis分布…

【单片机毕业设计8-基于stm32c8t6的RFID校园门禁系统】

【单片机毕业设计8-基于stm32c8t6的RFID校园门禁系统】 前言一、功能介绍二、硬件部分三、软件部分总结 前言 &#x1f525;这里是小殷学长&#xff0c;单片机毕业设计篇8基于stm32的RFID校园门禁系统 &#x1f9ff;创作不易&#xff0c;拒绝白嫖可私 一、功能介绍 -----------…

[Python图像识别] 五十二.水书图像识别 (2)基于机器学习的濒危水书古文字识别研究

该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门、OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子、图像增强技术、图像分割等,后期结合深度学习研究图像识别、图像分类应用。目前我进入第二阶段Python图像识别,该部分主要以目标检测、图像…

亚远景科技-ASPICE 4.0-HWE硬件过程的范围 The Technical Scope of HW process

ASPICE 4.0中的HWE process是电气和电子硬件的技术范畴&#xff0c;涵盖了硬件工程中的需求分析、设计和验证活动&#xff0c;但不包括以下活动&#xff1a; 1. 系统级工程过程。既不包括机电一体MECHATRONIC&#xff0c;也不包括ECU特定电子控制单元的开发。 2. 硬件采购过程…

Redis 与 MySQL 数据一致性问题

1. 什么是数据库与缓存一致性 数据一致性指的是&#xff1a; 缓存中存有数据&#xff0c;缓存的数据值 数据库中的值&#xff1b;缓存中没有该数据&#xff0c;数据库中的值 最新值。 反推缓存与数据库不一致&#xff1a; 缓存的数据值 ≠ 数据库中的值&#xff1b;缓存或…

什么是One-Class SVM

1. 简介 单类支持向量机&#xff0c;简称One-Class SVM(One-Class Support Vector Machine)&#xff0c;是一种用于异常检测的监督学习算法。其主要目标是找出数据集中的异常或罕见样本&#xff0c;而不需要大量的正常样本用于训练。这使其在处理高维数据和非常稀疏的异常检测问…

AutoCAD之DWF三维信息提取---linux编译篇

1. 权限 1.1 给文件添加执行权限 chmod x autogen.sh1.2.给当前文件下的所有文件改变为读写执行权限 chmod 777 * -R 2.环境安装 2.1安装automake 1.4.1 安装链接 安装中遇到的问题及解决 2.2安装autoconf 2.3 安装libtool 2.4 安装Cmake(CMake包含) cmake安装在cent…

GMSSL-通信

死磕GMSSL通信-C/C++系列(一) 最近再做国密通信的项目开发,以为国密也就简单的集成一个库就可以完事了,没想到能有这么多坑。遂写下文章,避免重复踩坑。以下国密通信的坑有以下场景 1、使用GMSSL guanzhi/GmSSL进行通信 2、使用加密套件SM2-WITH-SMS4-SM3 使用心得 ​…

影响小程序SSL证书收费标准的因素有哪些?

在当今互联网时代&#xff0c;移动应用发展日新月异&#xff0c;小程序逐渐成为广大企业和个人开发者的心仪之选。然而&#xff0c;伴随小程序的广泛应用&#xff0c;安全问题和用户信任显得尤为关键。为了确保小程序的信息传输安全&#xff0c;SSL证书成为了一项基础配置。那么…

【C++题解】1028 - 输入一个三位数,把个位和百位对调后输出

问题&#xff1a;1028 - 输入一个三位数&#xff0c;把个位和百位对调后输出 类型&#xff1a;基础问题 题目描述&#xff1a; 输入一个三位自然数&#xff0c;然后把这个数的百位数与个位数对调&#xff0c;输出对调后的数。 输入&#xff1a; 输入一行&#xff0c;只有一…

独一无二:探索单例模式在现代编程中的奥秘与实践

设计模式在软件开发中扮演着至关重要的角色&#xff0c;它们是解决特定问题的经典方法。在众多设计模式中&#xff0c;单例模式因其独特的应用场景和简洁的实现而广受欢迎。本文将从多个角度详细介绍单例模式&#xff0c;帮助你理解它的定义、实现、应用以及潜在的限制。 1. 什…