Monoxer Programming Contest 2024(AtCoder Beginner Contest 345)(A,B,C,D,E,F)

news2025/2/23 22:36:08

比赛链接

这场。。。好像已经是一周之前的比赛来着,终于补完了。

C是个披着字符串外衣的数学容斥题。D是个超级超级暴力的爆搜,写起来超级麻烦,感觉。。。真是一次酣畅淋漓的赤石。E是个DP,朴素想法其实比较直观,不过优化起来就很抽象了。F图论dfs跑一下就可以了,意外的简单。

一个我觉得讲的很好的视频讲解A-G(评论区里面有博客链接,放着讲解和代码)


A - Leftrightarrow

题意:

您将得到一个由“<”、“=”和“>”组成的字符串 S S S

判断 S S S 是否为双向箭头字符串。

字符串 S S S 是双向箭头字符串,当且仅当存在正整数 k k k ,使得 S S S 是一个“<”、 k k k “=`s和一个”>"的连接,按此顺序,长度为 ( k + 2 ) (k+2) (k+2)

思路:

判断一下给定字符串是不是第一个是 <,最后一个是 >,中间全是 = 就行了。

code:

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

string s;

int main(){
	cin>>s;
	if(s[0]=='<' && s[s.length()-1]=='>' && 
		s.substr(1,s.length()-2).find_first_not_of("=")==string::npos)
		puts("Yes");
	else puts("No");
	return 0;
} 

B - Integer Division Returns

题意:

如果给定一个介于 − 1 0 18 -10^{18} 1018 1 0 18 10^{18} 1018 之间的整数 X X X ,则打印 ⌈ X 10 ⌉ \left\lceil \dfrac{X}{10} \right\rceil 10X

这里, ⌈ a ⌉ \left\lceil a \right\rceil a 表示不小于 a a a 的最小整数。

思路:

C++的整数除法是向零取整,换句话说,对正数是向下取整,对负数是向上取整。

code:

#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;

ll x;

int main(){
	cin>>x;
	if(x<0)cout<<x/10;
	else cout<<(x+9)/10;
	return 0;
}

C - One Time Swap

题意:

您将得到一个字符串 S S S 。查找执行以下操作恰好一次可产生的不同字符串数。

  • N N N S S S 的长度。选择一对整数 ( i , j ) (i,j) (i,j) ,例如 1 ≤ i < j ≤ N 1\leq i \lt j\leq N 1i<jN ,并交换 S S S 的第 i i i 和第 j j j 个字符。

可以证明,在这个问题的约束条件下,你总是可以执行它。

思路:

暴力枚举交换的两个位置,并统计所有不同的串肯定是不行的。考虑怎么样会产生一次不同的串也很麻烦。所以正难则反,考虑怎么交换是会重复的,并用总的交换方式减去重复的即可。

不难发现相同字符交换的话得到的就是原串,这时候是重复的。所以我们统计每种字符出现的次数,用总的选择数减去每种字符从中选两个的选择数即可。

不过需要注意的是,一开始的串并没有算上,所以第一次相同字母交换得到的和原串相同的串也是会产生一次贡献,特判一下即可。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
typedef long long ll;

string s;
map<char,ll> mp;
ll n,ans;

int main(){
	cin>>s;
	for(auto x:s)mp[x]++;
	n=s.length();
	ans=n*(n-1)/2;
	bool flag=false;
	for(auto t:mp){
		ll x=t.second;
		if(!flag && x>1){
			ans+=1;
			flag=true;
		}
		ans-=x*(x-1)/2;
	}
	cout<<ans;
	return 0;
}

D - Tiling

题意:

存在 H H H 行和 W W W 列的网格,每个单元具有 1 1 1 的边长,

我们有 N N N 个瓷砖。

i i i 块( 1 ≤ i ≤ N 1\leq i\leq N 1iN )是一个大小为 A i × B i A_i\times B_i Ai×Bi 的矩形。

确定是否可以将瓷砖放置在网格上,以便满足以下所有条件:

  • 每个单元格都被正好一块瓷砖覆盖。
  • 可以有未使用的瓷砖。
  • 放置时,瓷砖可以旋转或翻转。

但是,每个瓷砖必须与网格的边缘对齐,而不会延伸到网格之外。

思路:

发现 H , W , N H,W,N H,W,N 非常小,考虑直接暴力。

先枚举所有的选取情况,然后对每种选取情况尝试放置在网格上。放某块砖的时候直接暴力枚举每个位置(假设枚举的位置是瓷砖的左上角),然后枚举旋转情况(因为是矩形,旋转两次 90 ° 90\degree 90° 相当于不旋转,翻转相当于没动,因此我们只需要验证不旋转和旋转一次 90 ° 90\degree 90° 即可)

这里可以稍微加个剪枝,就是对一种选取情况,选到的砖的总面积一定等于 H ∗ W H*W HW

code:

看着长,其实逻辑并不复杂,但是不妨碍这是一道粪题。

#include <iostream>
#include <cstdio>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;

int n,h,w;
pair<int,int> a[15];

bool pick[15];
bool vis[15][15];
bool checkprint(int x,int y,int idx){//检查是否可以放这块瓷砖
	if(x+a[idx].first-1>h || y+a[idx].second-1>w)return false;
	for(int i=x;i<x+a[idx].first;i++)
		for(int j=y;j<y+a[idx].second;j++)
			if(vis[i][j])
				return false;
	return true;
}
void print(int x,int y,int idx,bool st){//放/移除 这块瓷砖
	for(int i=x;i<x+a[idx].first;i++)
		for(int j=y;j<y+a[idx].second;j++)
			vis[i][j]=st;
}
bool checkprint2(int x,int y,int idx){//旋转90°再放
	if(x+a[idx].second-1>h || y+a[idx].first-1>w)return false;
	for(int i=x;i<x+a[idx].second;i++)
		for(int j=y;j<y+a[idx].first;j++)
			if(vis[i][j])
				return false;
	return true;
}
void print2(int x,int y,int idx,bool st){//旋转90°再放
	for(int i=x;i<x+a[idx].second;i++)
		for(int j=y;j<y+a[idx].first;j++)
			vis[i][j]=st;
}
vector<int> tt;
bool dfs2(int idx){//尝试放第idx块瓷砖
	if(idx>=(int)tt.size()){
		return true;
	}
//	cout<<idx<<endl;
	for(int x=1;x<=h;x++){
		for(int y=1;y<=w;y++){
			if(vis[x][y])continue;
			if(checkprint(x,y,tt[idx])){
				print(x,y,tt[idx],1);
				if(dfs2(idx+1))return true;
				print(x,y,tt[idx],0);
			}
			if(a[tt[idx]].first!=a[tt[idx]].second && checkprint2(x,y,tt[idx])){
				print2(x,y,tt[idx],1);
				if(dfs2(idx+1))return true;
				print2(x,y,tt[idx],0);
			}
		}
	}
	return false;
}
bool check(){//剪枝&检查这个旋转情况
	int tot=0;
	for(int i=1;i<=n;i++)
		if(pick[i])
			tot+=a[i].first*a[i].second;
	if(tot!=h*w)return false;
	
	tt.clear();
	for(int i=1;i<=n;i++)
		if(pick[i])
			tt.push_back(i);
	return dfs2(0);
}

void dfs(int idx){//枚举选举情况
	if(idx>n){
		if(check()){
			puts("Yes");
			exit(0);
		}
		return;
	}
	
	pick[idx]=true;
	dfs(idx+1);
	pick[idx]=false;
	dfs(idx+1);
}

int main(){
	cin>>n>>h>>w;
	for(int i=1;i<=n;i++){
		cin>>a[i].first>>a[i].second;
	}
	sort(a+1,a+n+1,[&](pair<int,int> a,pair<int,int> b){return a.first*a.second>b.first*b.second;});
	
	dfs(1);
	puts("No");
	return 0;
}

E - Colorful Subsequence

题意:

N N N 个球排成一排。

左起第 i i i 个球的颜色为 C i C_i Ci ,值为 V i V_i Vi 。Takahashi想要从这一行中删除精确的 K K K 个球,以便在剩余的球的排列中,没有两个相邻的球具有相同的颜色。

高桥希望在不改变顺序的情况下,将这一行中的 K K K 个球移除,这样在排列剩余的球时,就不会有相邻的两个球颜色相同。此外,在此条件下,他希望最大化这一行中剩余球的总价值。

请计算高桥是否能移除 K K K 个球,使剩下的一行中没有相邻的两个球颜色相同。如果可以,求剩余球的最大总值。

思路:

朴素的动态规划思路还是比较好想的。即设 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 表示前 i i i 个球删掉 j j j 个,最后一个球的颜色为 k k k 的最大剩余价值。枚举到第 i i i 个球时,可以通过删掉或者不删掉第 i i i 个球来转移,删掉则从 d p [ i − 1 ] [ j − 1 ] [ k ] dp[i-1][j-1][k] dp[i1][j1][k] 转移过来,不删掉则从 d p [ i − 1 ] [ j ] [ k ′ ] dp[i-1][j][k'] dp[i1][j][k] 转移过来( k ′ k' k 表示所有非 c i c_i ci 颜色的颜色)。

不过时间复杂度为 N ∗ K ∗ N N*K*N NKN 的,肯定爆掉了 。发现其实我们不需要知道那么多颜色的答案,因为我们只要保证转移过来时不撞颜色就行,所以要么是从最大价值的颜色转移过来,要么从除了这个颜色以外剩下的最大价值转移过来。因此我们第三维只需要存储最大的价值和颜色,以及除了这个颜色以外的最大的价值和颜色,这样时间复杂度就优化到了 N ∗ K ∗ 2 N*K*2 NK2

不过这时候空间复杂度也为 N ∗ K ∗ 2 N*K*2 NK2,会 M L E MLE MLE。考虑到我们第一维推到第 i i i 个位置的时候,它只和第 i − 1 i-1 i1 个位置的 d p dp dp 值有关,所以我们可以用滚动数组的思想来优化:我们只存储前一个位置和现在要推的位置的 d p dp dp 值即可。

话说得轻巧,但是写起来超级麻烦 ,真是一场畅快淋漓的赤石啊!

如果我们第三位存储两种颜色,即最大价值的颜色和次大价值的颜色,那么我们需要另开一个长度为 2 2 2 的颜色数组来存,然后我们更新答案的时候,就需要考虑到:尝试更新最大价值但是颜色冲突,更新最大价值但是颜色不冲突 ,更新次大价值但是颜色冲突,更新次大价值但是颜色不冲突。然后呢,更新最大价值的时候还要顺便更新次大情况,还要考虑到无解的情况。写到大脑空空,两眼逐渐智慧起来。在这里插入图片描述

然后没办法去借鉴题解了。

题解写法确实好 。我们不把颜色放在第三维度,而是把颜色当作一个信息,与最大价值一起存储起来,把所有可能的信息都存储在 d p dp dp 下。具体来说,设 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前 i i i 个球删掉 j j j 个的 所有 最大价值和最后一个球的颜色。代码实现如下:

typedef long long ll;
#define pll pair<ll,ll>
const vector<pll> infv={{-inf,-1},{-inf,-2}};
vector<vector<vector<pll> > > dp(2,vector<vector<pll> >(k+1,infv));

这串代码可以理解为一个二维的 v e c t o r vector vector,然后它存储的“值”是 v e c t o r < p l l > vector<pll> vector<pll> p l l pll pll 就是每个状态(最大价值和最后一个球的颜色) , v e c t o r < p l l > vector<pll> vector<pll> 其实就是把所有状态存进了一个 v e c t o r vector vector

这样书写的好处一个是我们可以把每个可能的情况都直接扔进 v e c t o r vector vector 里,而不需要马上讨论更新答案,最后再找 最大价值及颜色和次大价值及颜色。另外一个好处就是我们可以往里面扔两个价值很小且颜色不同的状态来占位置(也就是上面这串代码的 i n f v infv infv),这样就可以不用处理无解或者只有一种颜色的情况——价值小于0就是不符合的情况。

code:

最考C++语法的一集

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#define pll pair<ll,ll>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
const int maxk=505;
const ll inf=1e18;

int n,k;

int main(){
	cin>>n>>k;
	
	const vector<pll> infv={{-inf,-1},{-inf,-2}};
	vector<vector<vector<pll> > > dp(2,vector<vector<pll> >(k+1,infv));
	dp[0][0][0].first=dp[0][0][1].first=0;
	
	for(int i=1;i<=n;i++){
		ll c,v;
		cin>>c>>v;
		auto &pre=dp[(i-1)&1],&t=dp[i&1];
		for(int j=0;j<=k;j++)t[j]=infv;
		
		for(int j=1;j<=k;j++){//删掉第i个球 
			for(auto &x:pre[j-1]){
				t[j].push_back(x);
			}
		}
		for(int j=0;j<=k;j++){//不删第i个 
			for(auto &x:pre[j]){
				if(x.second!=c){
					t[j].push_back(pll(x.first+v,c));
					break;
				}
			}
		}
		
		for(int j=0;j<=k;j++){
			//排序去重
			sort(t[j].begin(),t[j].end(),greater<pll>());
			for(int k=1;k<t[j].size();k++){
				if(t[j][k].second!=t[j][0].second){
					swap(t[j][k],t[j][1]);
					break;
				}
			} 
			t[j].resize(2);
		}
		
	}
	
	ll ans=dp[n&1][k][0].first;
	if(ans>=0)cout<<ans<<endl;
	else cout<<-1<<endl;
	
	return 0;
}

F - Many Lamps

题意:

有一个简单图,其 N N N 个顶点编号为 1 1 1 N N N M M M 条边编号为 1 1 1 M M M 。边 i i i 连接顶点 u i u_i ui v i v_i vi

每个顶点都有一盏灯。最初,所有的灯都是熄灭的。在 0 0 0 M M M 次(包括 0 0 0 次和 M M M 次)之间执行以下操作,确定是否可以正好打开 K K K 盏灯:

  • 选择一条边。设 u u u v v v 是边的端点。切换 u u u v v v 上的灯的状态。

也就是说,如果灯亮了,就把它关掉,反之亦然。如果可以准确打开 K K K 盏灯,则打印实现此状态的操作序列。

思路:

直接看 上面说的题解 即可,讲的非常严谨了,没我什么事了。

这里提一嘴链式前向星的一个小性质:加入的第 i i i 条边在 e e e 数组中占第 2 ∗ i − 1 , 2 ∗ i 2*i-1,2*i 2i1,2i 的下标,这两条边是正反两个方向的,异或 1 1 1 可以相互切换。

code:

#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
const int maxn=2e5+5;

int n,m,k;

int head[maxn],cnt;
struct edge{
	int v,nxt;
}e[maxn<<1];
void add(int u,int v){
	e[++cnt].v=v;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}

bool vis[maxn],light[maxn];
int tot=0;
vector<int> ans;
void dfs(int u,int fa){
	vis[u]=true;
	for(int i=head[u],v;i;i=e[i].nxt){
		v=e[i].v;
		if(vis[v])continue;
		dfs(v,u);
		if(!light[v] && tot<k){
			light[v]=true;
			if(light[u])light[u]=false;
			else light[u]=true,tot+=2;
			ans.push_back((i+1)>>1);//上面说的链式前向星的存边小性质
		}
	}
}

int main(){
	cin>>n>>m>>k;
	if(k&1){
		cout<<"No";
		return 0;
	}
	for(int i=1,u,v;i<=m;i++){
		cin>>u>>v;
		add(u,v);
		add(v,u);
	}
	for(int i=1;i<=n;i++)
		if(!vis[i])
			dfs(i,-1);
	
	if(tot==k){
		cout<<"Yes\n"<<ans.size()<<endl;
		for(auto x:ans)
			cout<<x<<" ";
	}
	else cout<<"No";
	
	return 0;
}

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

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

相关文章

C# 右键快捷菜单(上下文菜单)的两种实现方式

在C#中&#xff0c;ContextMenuStrip是一种用于创建右键菜单的控件。它提供了一种方便的方式来为特定的控件或窗体添加自定义的上下文菜单选项。有两种实现方式&#xff0c;如下&#xff1a; 一.通过ContextMenuStrip控件实现 1.从工具箱中拖一个ContextMenuStrip控件到窗体上…

银行量子金融系统应用架构设计

量子金融&#xff08;即Financial-Quantum&#xff0c;简称Fin-Q&#xff09;&#xff0c;特指量子科技在金融行业中的应用。 目前&#xff0c;量子科技中以量子保密通信、量子随机数和量子计算发展进度较快&#xff0c;取得了诸多阶段性重大技术突破和商用成果&#xff0c;这…

vue学习日记13:记账清单,渲染添加删除

一.需求说明 二、实践 1.基本渲染 &#xff08;1&#xff09;代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" …

JAVA安全(偏基础)

SQL注入 SQLI(SQL Injection)&#xff0c; SQL注入是因为程序未能正确对用户的输入进行检查&#xff0c;将用户的输入以拼接的方式带入SQL语句&#xff0c;导致了SQL注入的产生。攻击者可通过SQL注入直接获取数据库信息&#xff0c;造成信息泄漏。 JDBC JDBC有两个方法获取s…

实时数仓之实时数仓架构(Doris)

目前比较流行的实时数仓架构有两类,其中一类是以Flink+Doris为核心的实时数仓架构方案;另一类是以湖仓一体架构为核心的实时数仓架构方案。本文针对Flink+Doris架构进行介绍,这套架构的特点是组件涉及相对较少,架构简单,实时性更高,且易于Lambda架构实现,Doris本身可以支…

Vue3中基本数据类型为什么需要.value,,,引用类型不需要.value

1、在v3中使用基本数据类型&#xff08;如数字、字符串、布尔值&#xff09;时&#xff0c;如果你希望响应式地更新数据并触发视图更新,需要使用ref包裹基本数据类型,然后将基本数据类型转化为响应式对象;- - - 因此当你使用ref包裹基本数据类型时,实际上得到的是一个包含.valu…

解读 Xend Finance:向 RWA 叙事拓展,构建更具包容性的 DeFi 体系

在二十世纪后&#xff0c;非洲地区陆续爆发了主权运动&#xff0c;这也让非洲大陆逐渐摆脱“殖民地”的标签。目前&#xff0c;非洲大陆公有 54 个主权国家&#xff0c;接近 15 亿且仍在飙升的人口规模&#xff0c;其 GDP 已经与印度相当&#xff0c;且仍旧处于飞速的发展进程中…

计算机服务器中了mkp勒索病毒怎么办,mkp勒索病毒解密工具流程

在网络飞速发展的时代&#xff0c;越来越多的企业离不开网络&#xff0c;利用网络可以为企业更好地开展各项工作业务&#xff0c;帮助企业有效调整发展方向与规划&#xff0c;但网络是一把双刃剑&#xff0c;在为人们提供便利的同时&#xff0c;也为企业的数据安全带来严重威胁…

【Apache ShenYu源码】如何实现负载均衡模块设计

ShenYu是一个异步的&#xff0c;高性能的&#xff0c;跨语言的&#xff0c;响应式的 API 网关。有关ShenYu的介绍可以戳这。 一、前瞻 今天我们尝试不同的代码阅读方式&#xff0c;按模块来去阅读源码&#xff0c;看看效果如何。 本次阅读锁定在shenyu-loadbalancer&#xf…

Qt登录页面

#include "mywidget.h" #include "ui_mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent), ui(new Ui::MyWidget) {ui->setupUi(this);//接收动图QMovie *mv new QMovie(":/pictrue/luori.gif");ui->loglab->setMovie(…

ssm项目(tomcat项目),定时任务(每天运行一次)相同时间多次重复运行job 的bug

目录标题 一、原因 一、原因 debug本地调试没有出现定时任务多次运行的bug&#xff0c;上传到服务器就出现多次运行的bug。&#xff08;war的方式部署到tomcat&#xff09; 一开始我以为是代码原因&#xff0c;或者是linux和win环境不同运行定时任务的方式不一样。 但是自己…

Chronicles 是什么数据库

可以理解的是 Chronicles 是 EPIC 公司根据 IRIS 进行魔改后的一个 DBMS。 简单的来说 Chronicles 就是一个数据库管理系统&#xff0c;但这个数据库管理系统不是我们常说的关系数据库的管理系统。 数据库结构 只要对数据库有所了解的都知道数据库通常就是 2 个部分&#xf…

基于Springboot的银行客户管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的银行客户管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

马斯克开源Grok-1

Grok-1是由马斯克AI创企xAI发布的第一代大语言模型&#xff0c;它以其巨大的参数量——高达3140亿&#xff0c;引起了全球范围内的广泛关注。这一参数量远超其他知名模型&#xff0c;如OpenAI的GPT-3.5&#xff0c;后者仅有1750亿参数。在2024年3月17日&#xff0c;马斯克宣布将…

进程的终止

进程的退出&#xff08;main函数的退出&#xff09; main函数的返回值叫做进程的退出码&#xff0c;该退出码表示进程执行的情况。例如&#xff1a;一个函数返回一个值时&#xff0c;我们要知道函数的执行情况&#xff0c;可以去看函数的返回值。 例子&#xff1a; 1 #include…

多数据源 - dynamic-datasource | 进阶 - 动态解析数据源

文章目录 内置解析器自定义解析器相关文章🗯️ 上节回顾:前节中,了解了 dynamic-datasource 的动态添加/移除数据源。 👉 本节目标:了解 dynamic-datasource 的进阶用法 - 动态解析数据源。 动态解析数据源:指数据源切换是不固定的,可以根据域名,根据 header 参数,根…

Linux系统编程(笔记)

1、认识计算机系统&#xff08;上&#xff09; 1.1、计算机系统由软硬件构成 1.2、总线 1.3、I/O设备 1.4、内存 1.5、处理器 1.6、计算机硬件组成 2、认识计算机系统&#xff08;下&#xff09; 2.1、什么是操作系统 2.2、Linux内核模块 2.3、操作系统管理硬件&#xff08;职…

Tensorflow2.0笔记 - 链式法则例子

本笔记简单记录链式法则的原理&#xff0c;关于链式法则&#xff0c;本身和高等数学中的链式求导法则是一样的&#xff0c;深度学习中相关资料可以参考这里&#xff1a; 【深度学习之美22】BP算法详解之链式法则 - 知乎10.5 什么是计算图&#xff1f;我们知道&#xff0c; 神经…

sizeof()的使用

sizeof() 可以计算元素个数 msdn对sizeof的原解释 sizeof是C语言中的一个关键字&#xff0c;计算类型或变量大小&#xff0c;单位是字节 #include <stido.h>int main() {int arr[10] { 0 };printf("%d\n", sizeof(arr));return 0; } 这里输出的值是 40&am…

Java安全 反序列化(4) CC1链-LazyMap版

Java安全 反序列化(4) CC1链-LazyMap版 实验环境:存在漏洞的版本 commons-collections3.1-3.2.1 jdk 8u71之后已修复不可利⽤ 文章目录 Java安全 反序列化(4) CC1链-LazyMap版一.跟踪挖掘CC1_LazyMap原理二.完整CC1_Lazy版Poc 接着上一篇文章我们通过ChainedTransFormer实现任意…