Codeforces Round 893 (Div. 2)补题

Buttons(Problem - A - Codeforces)

题目大意:有三排按钮数量分别为a,b,c,第一排只能由A按下,第二排只能由B按下,第三排可以被任意一个人按下,问两人轮流游戏,谁没有可以按的谁输,问如果都发挥最佳状态,谁会胜利。A先开始。

思路:显然是个简单的博弈论问题,为了保证对方没有按钮可以按,那么两者都先去按公共部分的按钮,然后再去按自己的。
如果公共按钮的个数为奇数,那么A按下最后一个公共按钮,B按一下自己的按钮后,又转换成A先手问题,那么就看谁的多,谁赢,如果一样那么就是B胜利。
如果为偶数,那么B按下最后一个公共按钮。直接看两者谁多谁赢,如果相等那么就是B赢。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		if(c%2) b--;
		if(a>b) printf("First\n");
		else printf("Second\n");
	}
}

The Walkway(Problem - B - Codeforces)

题目大意:一条路上有n个长凳和m个卖饼干的商家,小p带了无限块饼干,她将在满足以下条件的时候吃饼干:
1.从来没吃过
2.已经走过d个长凳还没吃
3.遇到卖饼干的商家
问如果删除一个卖饼干的商家,她最少吃多少块,在她吃的块数最少的情况下,最多有几个商家可以作为被删除的那一个。

思路:一排商家,删除某个,显然是贪心问题,贪心问题的核心就是找到不被影响的局部最优解。那么我们就要看看一个商家被删除带来的影响最多能延伸到哪里:

如图,显然c被删除后,a,b之间吃饼干的位置会发生改变,但是a之前和b之后的情况是不变的,因为只能删除一个,所以a,b是正常要吃饼干的,并不会影响这个区间之外的地方。那么c对这个区间内部的影响,我们可以先不考虑a,b位置,只看中间如果删除c的话会吃多少饼干。那么显然就是(b-a)/d-((b-a)%d==0),因为如果(b-a)%d==0,那么就说明b被算进去了,此时我们是不计算b的,只考虑中间部分。然后再看加上c之后会吃多少饼干:(c-a)/d-((c-a)%d)+(b-c)/d-((b-c)%d)+1,这里在算ac段的时候先把c去掉,最后再加起来,防止算重。那么如果去掉后要吃的饼干变少了,很显然就可以去掉。最后一个点再单独讨论一下即可,因为最后一个点后面没有了,而n位置可能会因为它的去掉要加1个,所以要单独讨论清楚。

现在还有一个地方需要证明,就是我们去掉后,如果能减少,那么不管去掉哪里减少的是一样的,这个我是有个地方没写完善,交了通过了才知道,但实际上用map统计一下也不麻烦。既然写题解,那么咱们还是不水,就用map统计一下就是。

#include<bits/stdc++.h>
using namespace std;
int s[200010];
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,m,d;
		scanf("%d%d%d",&n,&m,&d);
		s[0]=1;
		for(int i=1;i<=m;i++) scanf("%d",&s[i]);
		int cnt=0,mx=0;
		map<int,int>mp;
		for(int i=1;i<m;i++)//先不看最后一个
		{
			int a=s[i-1],b=s[i+1],c=s[i];
			int q=(b-a)/d- ((b-a)%d==0?1:0);
			int nq=(c-a)/d- ((c-a)%d==0?1:0) +(b-c)/d- ((b-c)%d==0?1:0) +1;
			if(nq>q) cnt++,mx=max(mx,nq-q),mp[nq-q]++;
		}
		//
		int q=(n-s[m-1])/d;
		int nq=(s[m]-s[m-1])/d-((s[m]-s[m-1])%d==0)+(n-s[m])/d+1;
		if(nq>q) cnt++,mx=max(mx,nq-q),mp[nq-q]++;
		int ans=0,tmp=1;//tmp标记左端点有没有被计算过
		for(int i=1;i<=m;i++)
		{
			ans += (s[i]-s[i-1])/d+tmp;
			if((s[i]-s[i-1])%d) tmp=1;//当前的右端点会变成下一个区间的左端点,所以要看这里有没有被计入
			else tmp=0;
		}
		//s[m]-n
		ans += (n-s[m])/d+tmp;//先统计出一个都不删的情况
		if(mp[mx]==0) cnt=m;//有可能去掉任何一块都不能产生改变
		else cnt=mp[mx];
		printf("%d %d\n",ans-mx,cnt);
	}
}

Yet Another Permutation Problem(Problem - C - Codeforces)

题目大意:现在有一个排列a[],我们以此来构造一个数组d[],使d[i]=gcd(a[i],a[i%n+1]),要使d[]中不同的种类数最多,输出排列的顺序。

思路:这里实际上就是a[i]和它后面那个数取最大公因数,a[n]和a[1]取最大公因数。我们如果按顺序排列,那么所有的d[i]都是1,显然是不合适的。那么如何才能使种类数尽可能的多呢,显然就是需要将有倍数关系的放在一块儿。那么具体该怎么排呢,我们先把样例中的输出的d[]算出来,那么我们后续构造的时候,就可以用构造结果与之比较了。我们尝试直接把每个数的二倍放在它后面,剩下的随便放,发现构造出来的d[]和样例的d[]相同,一交果然ac。

#include<bits/stdc++.h>
using namespace std;
int st[100010];
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		vector<int>p;
		memset(st,0,sizeof st);
		for(int i=1;i<=n;i++)
		{
			if(!st[i])
			{
				int d=i;
				while(d<=n)
				{
					if(!st[d])p.push_back(d);
					st[d]=1;
					d *= 2;
				}
			}
		}
		for(auto it:p) printf("%d ",it);
		printf("\n");
	}
}

Trees and Segments (Problem - D - Codeforces)

题目大意:现在有一排树,其中只有橡树和冷杉两种树,橡树用0表示,冷杉用1表示,现在我们可以进行k次反转操作,质检员来检查的标准是a*l0+l1,a是质检员喜欢的数,l0是0的个数,l1是1的个数。a是在1-n之间的数,我么想要知道a在取不同的值的情况下,a*l0+l1的最大值是多少。

思路:我们可以去枚举连续0的区间[l,r],假设这段区间要符合要求需要修改c次,那么还剩下k-c次修改操作,我们如果能找出在这么多次操作的情况下[1,l-1],[r+1,n]中可以获得的连续1的最大长度,那么问题就解决了。

所以现在的问题就转变成获得在不超过任意操作次数下,[1,l-1]和[r+1,n]中连续1的最大长度,这个可以用dp来处理。

我们一段一段来看:

先看前半段,定义dp[i][j]表示前i个中,操作次数不超过j次的情况下连续1的最大长度。

那么我们来看状态转移如何计算:

首先按照最后一个划分,那么就是第i个选不选的问题:

如果第i个不选,那么就是前i-1个,操作次数不超过j的情况下连续1的最大长度

如果第i个选,那么就是从i往前延伸,在操作不超过j的情况下最多能延伸到的位置。

我们先暴力实现一下再考虑优化:

for(int i=1;i<=n;i++)//以i为结尾
{
	for(int j=0;j<=k;j++)
	{
		dp[i][j]=dp[i-1][j];//第i个不选
		int c=0,z;
		for(z=i;z>=1;z--)
		{
			if(a[z]=='0') c++;
			if(c==j) break;
		}
		dp[i][j]=max(dp[i][j],i-z+1);
	}
}

 显然这里的三重循环时间复杂度有点高。

我们很容易发现,在第三层循环中有一些位置虽然没有到j,但是却可以用来更新操作不超过c的情况下的值,那么我们不如就来实时更新一下。另外第i个不选,无论是对哪个j来说,都是从前一个转移而来,我们可以把它独立出来。

另外这里我们可以先不限制操作次数,最后调用的时候限制一下即可。

for(int i=1;i<=n;i++)//以i为结尾
{
	for(int j=0;j<=n;j++) p[i][j]=p[i-1][j];//第i个不选
	int c=0;
	for(int z=i;z>=1;z--)
	{
		if(a[z]=='0') c++;
		p[i][c]=max(p[i][c],i-z+1);
	}
	for(int j=c;j<=k;j++) p[i][j]=max(p[i][j],p[i][c]);//这里不超过c的,自然也不超过大于c的情况,所以我们还是一并更新一下
}

ps:为了与后缀区分,改成p 

那么这里的时间复杂度就变成O(n^2)了。我们想要的也都更新出来了。

对于后缀的更新和这个同理:

for(int i=n;i>=1;i--)//以i为开头
{
	for(int j=0;j<=n;j++) q[i][j]=q[i+1][j];
	int c=0;
	for(int j=i;j<=n;j++)
	{
		if(a[j]=='0') c++;
		q[i][c]=max(q[i][c],j-i+1);
	}
	for(int j=c;j<=k;j++) q[i][j]=max(q[i][j],q[i][c]);
}

至此我们前缀后缀都处理出来了,那么现在实际上可以直接嵌套循环去枚举区间了,但是有一点要注意,我们最后要的只是不同a时的结果,枚举区间的时间复杂度是O(n^2),如果再嵌套一层a,那么就是O(n^3),显然时间复杂度高了。但是我们注意到,讨论a的时候,我们只关心l0和l1的值,对于它们是哪段区间的并不关心,那么我们就可以先枚举区间找出不同的l0对应的l1的值,然后在遍历a的时候只用遍历l0的值即可。

for(int i=1;i<=n;i++)
{
	int c=0;
	for(int j=i;j<=n;j++)
	{
		if(a[j]=='1') c++;
		int d=j-i+1;
		f[d]=max(f[d],max(p[i-1][k-c],q[j+1][k-c]));
	}
}

注意到,这里我们没有f[0]的情况,f[0]的话,那么就是全为1,不一定能得到这种情况,因为最多只能操作k次,但是如果能得到,那么1的个数应该是p[n][k],如果不能得到的话,也会有另一个值大于f[0]的情况,不会取到,所以,我们可以就令f[0]=p[n][k],至此就差不多解决了,最后再枚举一下a即可。

#include<bits/stdc++.h>
using namespace std;
int p[3010][3010],q[3010][3010],f[4000],ans[4000];
char a[4000];
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,k;
		scanf("%d%d",&n,&k);
		memset(f,-0x3f,sizeof f);
		memset(ans,-0x3f,sizeof ans);
		scanf("%s",a+1);
		
		for(int i=0;i<=n+1;i++)//前缀用到i-1,后缀用到i+1
			for(int j=0;j<=n;j++) 
				p[i][j]=q[i][j]=0;
	
		for(int i=1;i<=n;i++)//以i为结尾
		{
			for(int j=0;j<=n;j++) p[i][j]=p[i-1][j];//第i个不选
			int c=0;
			for(int z=i;z>=1;z--)
			{
				if(a[z]=='0') c++;
				p[i][c]=max(p[i][c],i-z+1);
			}
		}

		for(int i=n;i>=1;i--)//以i为开头
		{
			for(int j=0;j<=n;j++) q[i][j]=q[i+1][j];
			int c=0;
			for(int j=i;j<=n;j++)
			{
				if(a[j]=='0') c++;
				q[i][c]=max(q[i][c],j-i+1);
			}
		}

		for(int i=1;i<=n;i++)
		{
			int c=0;
			for(int j=i;j<=n;j++)
			{
				if(a[j]=='1') c++;
				if(c>k) break;
				int d=j-i+1;
				f[d]=max(f[d],max(p[i-1][k-c],q[j+1][k-c]));
			}
		}
		
		f[0]=p[n][k];
		for(int i=1;i<=n;i++)
		{
			for(int j=0;j<=n;j++)
			{
				ans[i]=max(ans[i],i*j+f[j]);
			}
		}
		for(int i=1;i<=n;i++) printf("%d ",ans[i]);
		printf("\n");
	}
}

这道题的核心点在于它要求在有条件限制下两个连续区间的最大长度,其实和(问题 H: 再会,谢谢所有的鱼 - BUCTOJ)这道题有点像,都是要找到两个不相交的连续区间,不过一个是要找区间的最长长度,一个是要找区间中的最大和,本质上都是要处理出以某个点为端点的一段区间的某个值,这里的这道题涉及到一个很妙的优化思路,就是上面所写的将三层循环降至两层循环的过程,因为很显然在查找的过程中,j是单增的关系,那么我们就可以在遍历的时候实时更新,进而降低时间复杂度。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

易语言系列学习1

通过本文章你会学习到 如果 如果真 获取编辑框内容 关闭本程序 监听按键让它等价于点击某个按钮 运算&#xff1a;或 且 非&#xff08;注意中间要有一个空格&#xff0c;否则会报错&#xff09; 效果 .版本 2.程序集 窗口程序集_启动窗口.子程序 _按钮2_被单击. 如果真 (编…

C#,斯特林数(Stirling Number)的算法与源代码

1 斯特林数 在组合数学&#xff0c;斯特林数可指两类数&#xff0c;第一类斯特林数和第二类斯特林数&#xff0c;都是由18世纪数学家James Stirling提出的。它们自18世纪以来一直吸引许多数学家的兴趣&#xff0c;如欧拉、柯西、西尔沃斯特和凯莱等。后来哥本哈根&#xff08;…

使用 postcss-cva 来生成 cva 方法吧

使用 postcss-cva 来生成 cva 方法吧 使用 postcss-cva 来生成 cva 方法吧 什么是 cva 封装示例组成参数 postcss-cva 的功能 Css 示例原子化设计注释参考生成cva函数 Refers 什么是 cva cva 全称为 class-variance-authority, 它是一个非常适合制作那种&#xff0c;创建控…

Ps:自动混合图层

Ps菜单&#xff1a;编辑/自动混合图层 Edit/Auto-Blend Layers 自动混合图层 Auto-Blend Layers命令可以自动地混合多个图层&#xff0c;特别适合于制作全景图、焦点堆叠、曝光合成或任何需要平滑融合多个图像的场景。 自动混合图层命令仅适用于 RGB 或灰度图像&#xff0c;不适…

2024年美国大学生数学建模B题思路分析 - 搜索潜水器

# 1 赛题 问题B&#xff1a;搜索潜水器 总部位于希腊的小型海上巡航潜艇&#xff08;MCMS&#xff09;公司&#xff0c;制造能够将人类运送到海洋最深处的潜水器。潜水器被移动到该位置&#xff0c;并不受主船的束缚。MCMS现在希望用他们的潜水器带游客在爱奥尼亚海底探险&…

shell脚本-免交互

一、Here Document免交互&#xff1a; 1.交互概述&#xff1a; 交互&#xff1a;当计算机播放某多媒体程序的时候&#xff0c;编程人员可以发出指令控制该程序的运行&#xff0c;而不是程序单方面执行下去&#xff0c;程序在接受到编程人员相应的指令后而相应地做出反应。 对于…

html,css,js速成

准备&#xff1a;vscode配好c&#xff0c;python&#xff0c;vue环境。 1. html hypertext markup language(超文本标记语言) 1. 基础语法 一个html元素由开始标签&#xff0c;填充文本&#xff0c;结束标签构成。 常见标签说明<b></b>粗体<i></i>…

UE4学习笔记 FPS游戏制作3 添加武器

文章目录 章节目标为骨骼添加武器挂载点添加武器 章节目标 本章节为手部添加一个武器挂载点&#xff0c;并挂载一个武器 为骨骼添加武器挂载点 添加挂载点需要以一个动画片段为基础&#xff0c;为骨骼添加挂载点。 首先找到我们需要的动画片段&#xff0c;通常是idle 双击打…

CentOS 7中搭建NFS文件共享服务器的完整步骤

CentOS 7中搭建NFS文件共享服务器的完整步骤 要求&#xff1a;实现镜像文件共享&#xff0c;并基于挂载的共享目录配置yum源。 系统环境&#xff1a; 服务器&#xff1a;172.20.26.167-CentOS7.6 客户端&#xff1a;172.20.26.198-CentOS7.6 1、在服务器和客户端上&#x…

AI 原生时代的云计算

本文整理自2023年 12 月 20 日举办的「2023 百度云智大会智算大会」主论坛&#xff0c;百度副总裁谢广军的主题演讲《AI 原生时代的云计算》。 &#xff08;视频回放链接&#xff1a;https://cloud.baidu.com/summit/aicomputing_2023/index.html&#xff09; 大模型的到来&…

leetcode 19 , 118

19 .删除链表倒数第n个节点 思路1&#xff1a; 我首先想到的就是使用两个loop来进行解决&#xff1a; 遍历所有节点&#xff0c;得到需要删除节点的位置。再遍历一边所有节点&#xff0c;找到需要删除节点进行删除。 解决方案1&#xff1a; class Solution {public ListNod…

深入探究iframe:网页嵌入的魔法盒子(上)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

2024/2/1学习记录

echarts 为柱条添加背景色&#xff1a; 若想设置折线图的点的样式&#xff0c;设置 series.itemStyle 指定填充颜色就好了&#xff0c;设置线的样式设置 lineStyle 就好了。 在折线图中倘若要设置空数据&#xff0c;用 - 表示即可&#xff0c;这对于其他系列的数据也是 适用的…

Java知识点总结

数据类型强转&#xff1a;byte short int long float double &#xff1b; 数组定义 [ ]数组名 clone-复制数组equals-比较存储地址 toString sort-排序 length-长度 arraycopy([]a,s,[]b,ss,n)-数组复制 运算符及语句 instanceof双目运算符 –左对象右类 判断是否是该类创建…

OpenCV学习记录——边缘检测

文章目录 前言一、边缘检测原理二、Canny边缘检测算法三、具体应用代码 前言 在做某些图像处理时&#xff0c;通常需要将识别到的物体边界提取出来&#xff0c;从而帮助我们实现目标检测&#xff0c;这就需要用到边缘检测&#xff0c;例如人脸识别和运动目标的检测都需要先进行…

docker镜像命令

docker images 列表本机上的镜像 - REPOSITORY&#xff1a;表示镜像的仓库源 - TAG&#xff1a;镜像的标签 - IMAGE ID&#xff1a;镜像 - ID CREATED&#xff1a;镜像创建时间 - SIZE&#xff1a;镜像大小 同一仓库源可以有多个 TAG&#xff0c;代表这个仓库源的不同个版本&am…

亚信安全助力宁夏首个人工智能数据中心建成 铺设绿色算力安全底座

近日&#xff0c;由宁夏西云算力科技有限公司倾力打造&#xff0c;亚信安全科技股份有限公司&#xff08;股票代码&#xff1a;688225&#xff09;全力支撑&#xff0c;总投资达数十亿元人民币的宁夏智算中心项目&#xff0c;其一期工程——宁夏首个采用全自然风冷技术的30KW机…

FairGuard游戏加固入选《CCSIP 2023中国网络安全行业全景册(第六版)》

2024年1月24日&#xff0c; FreeBuf咨询正式发布《CCSIP 2023中国网络安全行业全景册(第六版)》。本次发布的全景图&#xff0c;共计展示20个一级分类、108个细分安全领域&#xff0c;旨在为广大企业提供网络安全产品选型参考&#xff0c;帮助企业了解中国网络安全技术与市场的…

部署前后端分离项目详细教程

部署前后端分离项目详细教程 1、准备工作 首先你需要一台服务器&#xff0c;然后在服务器上安装好你所需要的环境&#xff0c;我这里用的宝塔界面来安装环境。 如果有人不知道怎么安装宝塔界面&#xff0c;可参考这篇文章&#xff0c;如果不知道怎么买服务器&#xff0c;可以参…

硅谷仿制网易云小程序登录问题解决

引言&#xff1a; 尚硅谷视频中的登录拥挤问题&#xff0c;导致无法登录&#xff0c;所以&#xff0c;我去gitee上从新找了个别人搞好点网易云的api接口【也是比较出名的那个&#xff0c;不想用不行啊&#xff0c;我也试过很多方法都不行】 接口详解网址&#xff1a;网易云音乐…