Codeforces Round 911 (Div. 2)补题

Cover in Water

题目大意:我们有一排房间,一些房间是空的,一些房间是阻塞的,现在需要将所有的空房间都填满水,我们能做的只有两个操作:1.往一个空房间内放入水;2.将一个房间中的水取出放入另一个房间。另外当一个房间的左右两个房间都有水的时候,这个房间会自己产生水,我们需要尽可能地减少操作1的执行次数,问最少需要多少次操作1.

思路:由于左右两个房间有水,中间那个房间会自然产生水,所以可以发现如果有3个连在一起的房间,那么我们只需要放入两份水,中间空一个空房间,那么这个空房间产生水,我们把它移到别的空房间,那么它又会产生新的水,即只要有大于等于三个房间连在一起,那么就可以无限产生水,否则就要一个一个房间放入。那么我们需要统计的只有两个值,一个是空房间的总数,一个是是否有大于等于3个的空房间连在一起。

#include<bits/stdc++.h>
using namespace std;
char s[200];
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d%s",&n,s);
		char c=s[0];
		int cnt,sum;
		int mx=0;
		if(c=='#') cnt=sum=0;
		else cnt=sum=1;
		for(int i=1;i<n;i++)
		{
			if(s[i]=='.') 
			{	
				sum++;
				if(s[i]==c) cnt++,mx=max(cnt,mx);
				else cnt=1,mx=max(cnt,mx);
			}
			else cnt=0;
			c=s[i];
		}
		if(mx>=3) printf("2\n");
		else printf("%d\n",sum);
	}
}

Laura and Operations

题目大意:黑板上有若干个数,只有1,2,3三种,我们每次可以选择两个不同的数并擦除,然后添加一个不同于两者的数,问最后能否使黑板上所有的数都相同,如果有可能,那么会是哪些数。输入给出三个数各自的数量,输出只用输出0,1(0表示这个数最终不可能出现,1表示这个数最终有可能出现)

思路:首先,如果有两个数的个数相等,那么第三个数一定可以得到,否则,我们来仔细考虑一下,不管怎么样就算两个不相等,也要想办法使它们相等,该怎么使它们相等呢,一个方法是用目标数字和多的那个来生成少的那个,最后使两者相等,多的减少的和少的增加的是一样多的,那么就证明它们的差值是偶数;另外如果目标的数量太少没办法使两者相等怎么办,我们可以先将两个都减少,用来生成目标,然后再用目标和多的去生成少的,使多的和少的数目相等,那么条件也是它们的差值是偶数。至此问题解决,核心就是要另外两个相等,或者能变成相等的。

#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(b==c||(b+c)%2==0) printf("1 ");
		else printf("0 ");
		if(a==c||(a+c)%2==0) printf("1 ");
		else printf("0 ");
		if(b==a||(b+a)%2==0) printf("1 ");
		else printf("0 ");
		printf("\n");
	}
}

Anji's Binary Tree

题目大意:有一颗n节点的二叉树,1是根节点,我们对于每个节点输出它的左子节点和右子节点(0表示该节点为空),同时每个节点有一个字母,U表示返回父节点,R表示移动到右子节点,L表示移动到左子节点,如果该操作不合法则停止不动。我们想到任意一个叶子节点(没有子节点的点)去,可以修改任意一个节点处的操作,问最少修改多少次可以保证我们最终可以到达叶子节点。

思路:本来想的是记录所有的叶子节点,以及每个点的父节点的下标及到这个子节点需要进行的操作,我们遍历所有的叶子节点,并往回找知道访问到1,当父节点处的实际操作和到叶子节点的操作不同时,操作数自增,对于每个叶子节点求出需要的操作数,从中取最小值,理论上每个样例的时间复杂度是nlogn,不应该超时,但是很不幸,还是超时了。而且没办法优化,所以只能换思路。我们刚刚的思路是从后往前找,既然不成立,那么只能考虑遍历二叉树,用动态规划的思想来更新到每个节点的操作数,最后从所有叶子节点的操作数中找出最小值。实际上我感觉相比前一种方法,我们还多遍历了一些点,因为前一种方法不在路径上的点不会被遍历到,这种方法所有的点都会被遍历(这里分析有问题,前面的点会被反复访问),但是很奇怪,这个方法确实没有超时,并且AC了。不对,时间复杂度不能这么分析。

我重新分析了下,过程如下:
 

for(int i=0;i<e.size();i++)
{	
	int x=e[i];
	int op=0;
	while(x!=1)
	{
		if(s[v[x].first]!=v[x].second)  op++;
		x=v[x].first;
	}
	mi=min(mi,op);
	if(!mi) break;
}

这个是第一种方法的查找部分,我们假设一下一共有m层,每层都是满的,即n=2^m-1,那么就有2^(m-1)个叶子节点,每个叶子节点需要执行m次while(),那么时间复杂度就是m*2^(m-1),log(n+1)*(n+1)/2,即相当于nlogn,但是对于第二种方法,dfs只会把所有节点遍历一遍,时间复杂度是n,所以实际上还是快一点,所以应该是这个logn被卡了。

#include<bits/stdc++.h>
using namespace std;
char s[300010];
int l[300010],r[300010];
int dp[300010];
void dfs(int x)
{
	if((!l[x]&&!r[x])||!x) return; 
	dp[l[x]]=dp[r[x]]=dp[x];
	if(s[x]=='L') dp[r[x]]++;
	else if(s[x]=='R') dp[l[x]]++;
	else dp[l[x]]++,dp[r[x]]++;
	dfs(l[x]);
	dfs(r[x]);
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		scanf("%s",s+1);
		vector<pair<int,char>>v(n+10);
		vector<int>e;
		for(int i=1;i<=n;i++) l[i]=r[i]=dp[i]=0;
		for(int i=1;i<=n;i++)
		{
			int a,b;
			scanf("%d%d",&a,&b);
			l[i]=a,r[i]=b;
			if(!a&&!b) e.push_back(i);
		}
		dfs(1);
		int mi=n+10;
		for(int i=0;i<e.size();i++)
		{	
			int x=e[i];
			mi = min(mi,dp[x]);
		}
		printf("%d\n",mi);
	}
}

ps:对于二叉树,遍历比访问路径的效率更高,修改可以用dp来累计和转移。

Small GCD

题目大意:有一个数组a[],我们定义运算f(x,y,z):将x,y,z排序使x<=y<=z,f(x,,y,z)=gcd(x,y),求\sum_{i=1}^{n} \sum_{j=i+1}^{n} \sum_{k=j+1}^{n}f(ai,aj,ak)

思路:我们可以发现一些数比如最小的两个,在它们同时与其他数组合的时候,f()的值始终是它们俩的最大公因数,所以我们想到排序,将循环从三维降成二维,那么总的时间复杂度就是t*n*n,看上去能卡着过去,但实际上gcd的时间复杂度也要考虑,gcd(x,y)的时间复杂度即O(log(min(x,y))),所以我们即使优化了,还是照样超时(如果n的范围是<=3e3就可以实现)。所以,我们就要想新的方法来优化。 

这题需要用到数论里的欧拉反演。本题欧拉反演部分的证明

核心的转化如下:
 

我感觉代码更直观,我就将链接中的公式推演全部转化成代码了,就从上一个思路的末尾开始讨论详细转化如下:

for(int j=1;j<=n;j++)
{
	for(int i=1;j<=j-1;j++)
	{
		ans += gcd(a[i],a[j])*(n-j);
	}
}

//欧拉公式
int sum=0;
for(int i=1;i<=n;i++)
{
	if(n%d==0) sum += phi(d);
}
=>sum==n;

|
V

for(int j=1;j<=n;j++)
{
	for(int i=1;j<=j-1;j++)
	{
		for(int d=1;d<=m;d++)
			if(gcd(a[i],a[j])%d==0) ans += phi(d)*(n-j);
	}
}

for(int j=1;j<=n;j++)
{
	for(int d=1;d<=m;d++)
	{	
		for(int i=1;j<=j-1;j++)
		{
			if(gcd(a[i],a[j])%d==0) ans += phi(d)*(n-j);
		}
	}
}

for(int j=1;j<=n;j++)
{
	for(int d=1;d<=m;d++)
	{	
		for(int i=1;j<=j-1;j++)
		//if(gcd(a[i],a[j])%d==0)这个条件成立的话,phi(d)*(n-j)会被加入ans一次,[]这个有0和1两种值,刚好用来替换if
		{
			 ans += [d|gcd(a[i],a[j])]*phi(d)*(n-j);
	    }
	}
}

for(int j=1;j<=n;j++)
{
	for(int d=1;d<=m;d++)
	{
		for(int i=1;j<=j-1;j++)
		{
			//d可以被两者的最大公因数整除,自然也可以被两者分别整除
			 ans += [d|a[i]]*[d|a[j]]*phi(d)*(n-j);
		}
	}
}

for(int j=1;j<=n;j++)
{	
	for(int d=1;d<=m;d++)
	{	
		if(a[j]%d==0)//将[d|a[j]]替换成if判断
		{
			for(int i=1;j<=j-1;j++)
			{
				ans += [d|a[i]]*phi(d)*(n-j);
			}
		}
	}
}


//令sum([d|ai])(1<=i<=j-1)=g(d)

for(int j=1;j<=n;j++)
{	
	for(int d=1;d<=m;d++)
	{	
		if(a[j]%d==0) 
			ans += g(d)*phi(d)*(n-j); //g(d)相当于1-(j-1)中d的倍数的个数
	}
}

//d是a[j]的因数,我们可以先将它预处理出来,得到v[a[j]]数组,那么就不用循环所有的数,只用循环v[a[i]]数组即可
for(int j=1;j<=n;j++)
{
	for(auto d:v[a[j]])
	{
		ans += g(d)*phi(d)*(n-j);
	}
}


//另外由于g(d)表示的是数组中的数在1~(j-1)范围内d的倍数的个数,那么我们直接在从小到大遍历的过程中统计一下即可
for(int j=1;j<=n;j++)
{
	for(auto d:v[a[j]])
	{
		ans += g(d)*phi(d)*(n-j);
		//a[j]是d的倍数,那么g[d]++;
		g[d]++;
	}
}

现在需要计算phi(d),计算参考了线性筛计算欧拉函数,核心代码如下:

	phi[1]=1;
	for(int i=2;i<=N;i++) 
	{
		if(!st[i]) phi[i]=i-1,prime.push_back(i);
		for(auto j:prime)
		{
			if(i*j>N) break;
			st[i*j]=1;
			if(i%j)
			{
				phi[i*j]=phi[i]*(j-1);
			}
			else 
			{
				phi[i*j]=phi[i]*j;
				break;
			}
		}
	}

另外g(d)的计算也涉及到一些技巧,g(d)的含义是a[1]-a[j-1]之间d的倍数有多少个,挨个统计太麻烦,我们前面已经预处理了每个a[i]的因子,那么我们访问一个a[i]的时候,它所有因子的倍数多出现了一个,那么我们就将它所有因子d的g[d]++,那么g[d]同样能表示d的倍数的出现次数。至此所有细节都讨论清楚了。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int phi[N+10],g[N+10],a[N+10];
vector<int>prime,v[N+10];
int st[N+10];
int main()
{
	phi[1]=1;
	for(int i=2;i<=N;i++) 
	{
		if(!st[i]) phi[i]=i-1,prime.push_back(i);
		for(auto j:prime)
		{
			if(i*j>N) break;
			st[i*j]=1;
			if(i%j)
			{
				phi[i*j]=phi[i]*(j-1);
			}
			else 
			{
				phi[i*j]=phi[i]*j;
				break;
			}
		}
	}
	for(int i=1;i<=N;i++)
	{
		for(int j=i;j<=N;j+=i)
		{
			v[j].push_back(i);
		}
	}
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		sort(a+1,a+1+n);
		memset(g,0,sizeof g);
		long long ans=0;
		for(int j=1;j<=n;j++)
		{
			for(auto d:v[a[j]])
				ans += 1ll*g[d]*phi[d]*(n-j),g[d]++;;
		}
		printf("%lld\n",ans);
	}
}

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

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

相关文章

UEM 在企业 IT 管理数字化转型有什么帮助

近年大多数公司都在努力实现数字化转型&#xff0c;业务应用程序正在迁移到云端&#xff0c;日常 IT 运营正变得更加面向移动化&#xff0c;高管们使用各种设备。员工不仅使用公司提供的台式机&#xff0c;还经常使用公司拥有的、个人启用的&#xff08;COPE&#xff09;笔记本…

基于springboot实现的宠物医院管理系统

一、系统架构 前端&#xff1a;html | jquery | echarts | css 后端&#xff1a;springboot | thymeleaf | mybatis 环境&#xff1a;jdk1.8 | mysql | maven 二、代码及数据库 三、功能介绍 01. 登录页 02. 系统设置-用户管理 03. 系统设置-页面管理 04. 系统设置-角…

接口测试方向

一、Http接口测试 前面我们已经有了接口文档&#xff0c;那么我们就要根据接口文档来拼接参数调用接口&#xff0c;那么怎么调用呢&#xff1f; 1、接口请求报文拼接---传参方式 1&#xff09;key-value形式 这种是最简单的一种&#xff0c;问号前面是请求url&#xff0c;后…

Liunx系统使用超详细(四)~文件/文本相关命令2

承接文章Liunx系统使用超详细(四)~文件/文本相关命令1http://t.csdnimg.cn/f7G6S 目录 一、awk命令(三剑客之一) 1.1工作原理 1.2工作流程 1.3语法格式 1.3.1格式注释&#xff1a; 1.3.2模式&#xff08;pattern&#xff09;的类型&#xff1a; 1.3.3动作&#xff08;ac…

【动态规划系列】环形子数组的和-918

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Java面试题(每天10题)-------连载(45)

Dubbo篇 1、Dubbo的服务调用流程 2、Dubbo支持那种协议&#xff0c;每种协议的应用场景&#xff0c;优缺点&#xff1f; dubbo&#xff1a; 单一长连接和 NIO 异步通讯&#xff0c;适合大并发小数据量的服务调用&#xff0c;以及消费者远大于提供者。传输协议 TCP&#xff0c;…

题目:纪念品分组(蓝桥OJ 532)

题目描述&#xff1a; 解题思路&#xff1a; 本题使用贪心思想&#xff0c;先排序&#xff0c;则最大和最小就分别位于头部和尾部。如果最大和最小之和不超过容量&#xff0c;就取两个放到一个&#xff08;ans&#xff09;并去除&#xff1b;如果最大和最小之和超过容量&#x…

域名与SSL证书

域名是互联网上的地址标识符&#xff0c;它通过DNS&#xff08;Domain Name System&#xff09;将易于记忆的人类可读的网址转换为计算机可以理解的IP地址。当用户在浏览器中输入一个网址时&#xff0c;实际上是通过DNS解析到对应的服务器IP地址&#xff0c;从而访问到相应的网…

C //例10.5 有一个磁盘文件,内有一些信息。要求第1次将它的内容显示在屏幕上,第2次把它复制到另一文件上。

C程序设计 &#xff08;第四版&#xff09; 谭浩强 例10.5 例10.5 有一个磁盘文件&#xff0c;内有一些信息。要求第1次将它的内容显示在屏幕上&#xff0c;第2次把它复制到另一文件上。 IDE工具&#xff1a;VS2010 Note: 使用不同的IDE工具可能有部分差异。 代码块 方法&a…

Web前端 ---- 【Vue】Vuex的使用(辅助函数、模块化开发)

目录 前言 Vuex是什么 Vuex的配置 安装vuex 配置vuex文件 Vuex核心对象 actions mutations getters state Vuex在vue中的使用 辅助函数 Vuex模块化开发 前言 本文介绍一种新的用于组件传值的插件 —— vuex Vuex是什么 Vuex 是一个专为 Vue.js 应用程序开发的状态…

STM32CubeIDE(CUBE-MX hal库)----RTC时钟,时钟实时显示

系列文章目录 STM32CubeIDE(CUBE-MX hal库)----初尝点亮小灯 STM32CubeIDE(CUBE-MX hal库)----按键控制 STM32CubeIDE(CUBE-MX hal库)----串口通信 STM32CubeIDE(CUBE-MX hal库)----定时器 STM32CubeIDE(CUBE-MX hal库)----蓝牙模块HC-05&#xff08;详细配置&#xff09; 前言…

PostGIS学习教程十一:投影数据

PostGIS学习教程十一&#xff1a;投影数据 地球不是平的&#xff0c;也没有简单的方法把它放在一张平面纸地图上&#xff08;或电脑屏幕上&#xff09;&#xff0c;所以人们想出了各种巧妙的解决方案&#xff08;投影&#xff09;。 每种投影方案都有优点和缺点&#xff0c;一…

干货!MES系统选型必须要考虑的9点要素!

你所在的企业是否为这些问题困扰&#xff1f; 纸质化管理混乱物料供应不及时设备数据难采集生产进度难透明 如果是的话&#xff0c;你的企业需要MES系统的帮助&#xff01; MES是制造执行系统&#xff08;Manufacturing Execution System&#xff09;的缩写。它是一种信息系…

Redis 环境搭建

文章目录 第1关&#xff1a;Redis 环境搭建 第1关&#xff1a;Redis 环境搭建 编程要求 根据上述相关知识&#xff0c;在右侧命令行中完成 Redis 集群的部署与安装。 安装完成后&#xff0c;使用 echo “cluster nodes”|redis-cli -p 7001 -c >/root/test.txt 将结果保存。…

外贸网站建站的注意事项?海洋建站的流程?

外贸网站建站需要注意什么&#xff1f;网站建设要注意哪些问题&#xff1f; 在建设外贸网站时&#xff0c;有一些关键的注意事项需要牢记&#xff0c;以确保网站的成功运营。海洋建站将介绍一些重要的外贸网站建站注意事项&#xff0c;帮助企业避免一些常见的陷阱和错误。 外…

架构师进阶,微服务设计与治理的 16 条常用原则

今天将从存储的上一层「服务维度」学习架构师的第二项常用能力 —— 微服务设计与治理。 如何设计合理的微服务架构&#xff1f; 如何保持微服务健康运行&#xff1f; 这是我们对微服务进行架构设计过程中非常关注的两个问题。 本文对微服务的生命周期定义了七个阶段&#x…

C //习题10.3 从键盘输入一个字符串,将其中的小写字母全部转换成大写字母,然后输出到一个磁盘文件“test“中保存,输入的字符串以“!“结束。

C程序设计 &#xff08;第四版&#xff09; 谭浩强 习题10.3 习题10.3 从键盘输入一个字符串&#xff0c;将其中的小写字母全部转换成大写字母&#xff0c;然后输出到一个磁盘文件"test"中保存&#xff0c;输入的字符串以"!"结束。 IDE工具&#xff1a;V…

MongoDB数据库时区问题

1.问题描述&#xff1a; 利用MongoTemplate类更新mongodb集合中的指定日期字段时&#xff0c;用mongodb可视化工具Robo3t查看所更新的字段&#xff0c;发现数据库中显示时间当前时间&#xff08;东8区区时&#xff09;早了8个小时。 2.产生原因&#xff1a; MongoDB默认的是…

骨传导原理是什么?使用骨传导耳机的危害有哪些?

骨传导耳机顾名思义&#xff1a;就是利用骨传导技术传递声音的耳机&#xff0c;骨传导的传声方式是通过颅骨震动来进行传导&#xff0c;将声音传到颅骨&#xff0c;在通过颅骨直接传导到内耳&#xff0c;因此不需要将声音通过耳膜来进行传递&#xff0c;即使用双手捂住耳朵也可…

【Java基础篇 | 面向对象】—— 聊聊什么是接口(上篇)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【JavaSE_primary】 本专栏旨在分享学习JavaSE的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 关于接口的简单的介绍…
最新文章