【AcWing】蓝桥杯集训每日一题Day7|贡献法|4261.孤独的照片(C++)

news2024/11/26 10:42:09
4261.孤独的照片
AcWing 4261. 孤独的照片(每日一题) - AcWing
难度:简单
时/空限制:1s / 64MB
总通过数:9889
总尝试数:26088
来源:

USACO 2021 December Contest Bronze
算法标签

贡献法乘法原理

题目内容

Farmer John 最近购入了 N 头新的奶牛,每头奶牛的品种是更赛牛(Guernsey)或荷斯坦牛(Holstein)之一。
奶牛目前排成一排,Farmer John 想要为每个连续不少于三头奶牛的序列拍摄一张照片。
然而,他不想拍摄这样的照片,其中只有一头牛的品种是更赛牛,或者只有一头牛的品种是荷斯坦牛——他认为这头奇特的牛会感到孤立和不自然。
在为每个连续不少于三头奶牛的序列拍摄了一张照片后,他把所有「孤独的」照片,即其中只有一头更赛牛或荷斯坦奶牛的照片,都扔掉了。
给定奶牛的排列方式,请帮助 Farmer John 求出他会扔掉多少张孤独的照片。
如果两张照片以不同位置的奶牛开始或结束,则认为它们是不同的。

输入格式

输入的第一行包含 N。
输入的第二行包含一个长为 N 的字符串。如果队伍中的第 i 头奶牛是更赛牛,则字符串的第 i 个字符为 G。否则第 i 头奶牛是荷斯坦牛,该字符为 H

输出格式

输出 Farmer John 会扔掉的孤独的照片数量。

数据范围

3≤N≤5×10^5

输入样例:
5
GHGHG
输出样例:
3
样例解释

这个例子中的每一个长为 3 的子串均恰好包含一头更赛牛或荷斯坦牛——所以这些子串表示孤独的照片,并会被 Farmer John 扔掉。
所有更长的子串(GHGHHGHGGHGHG)都可以被接受。

题目解析
贡献法

是一个数学思想,在枚举一些数的时候,有些枚举可能比较难算,可能换一种枚举方式比较好算
比如要统计矩阵里面所有数的和
如果按行统计比较复杂,按列统计比较简单,就按列统计
换一种统计的方式,就叫贡献法
看每一列对答案的贡献是什么
按行去统计的话,就是计算每一行它所有数的和
按列去统计的话,就是计算每一列所有数的和,再相加
第i列的总和,可以看成是第i列对整个总和的贡献

  1. 购入了N头牛,每头牛是更赛牛或荷斯坦牛
  2. 所有牛排成一排
  3. 枚举其中所有连续的不少于三头牛的区间,区间的数量是 O ( N 2 ) O(N^2) O(N2)
  4. 判断其中有多少个区间,里边有一种牛只有一头,有孤独的牛的话,就要扔掉
    统计一共有多少张照片是孤独的,统计多少个区间里边,某一个字符只出现一次
    N是50万,所以需要将时间复杂度控制在 O ( n log ⁡ 2 n ) O(n\log_{2}n) O(nlog2n)级别
暴力枚举

根据题目直接算的话,可以先去枚举所有区间,要枚举起点和终点,就是 O ( n 2 ) O(n^2) O(n2)级别
再统计区间内的每一个字符的出现次数 O ( n ) O(n) O(n)
过不去

换一种观察角度

在矩阵里边,如果每个区间是以行的话,牛如果是列的话,每一个区间里面如果相片是孤独的话,它一定对应一条唯一的孤独的牛,
所以每一个孤独的区间,跟一头牛是一一对应的
**切入点:**孤独区间一定会对应一头孤独的牛
但是一头牛不一定只对应一个区间

想统计孤独区间的数量的话,
如果暴力,先枚举区间,再去找孤独的牛
如果区间是行的话,有 O ( n 2 ) O(n^2) O(n2)级别个,在这 O ( n 2 ) O(n^2) O(n2)级别个中去找出所有孤独的区间的话:
如果第一个区间是孤独的区间,其中一定会存在一头孤独的牛,在孤独的牛这里标记为1,其余的牛都写成0
这样如果想统计孤独区间的数量,就可以换一种角度去统计,可以按列去统计,
统计一下第一头牛是多少个孤独区间的那一头孤独的牛,就是统计第一头牛对答案的贡献,

000100
100000
000010
100000
000100

如果第一头牛在两个区间里面是孤独的牛,就认为第一头牛对答案的贡献是2,第二头牛是0,第三头牛是0,第四头牛是2
这样子也可以把答案统计出来

时间复杂度可以做一些优化

假设改去枚举牛的话
一旦牛确定了,考虑一下一共有多少个区间是以这头牛为核心的孤独的区间
要考虑的区间肯定要包含这头牛,这个区间的左端点一定要在这头牛的左边,右端点应该在这头牛的右边,如果这头牛是孤独的牛的话,那么它的左右边一定是与它相对的那些牛

所有这样的区间要有多少个呢

这种统计次数是可以优化的,先统计一下左边有多少个连续的数量L,再统计一下右边连续的数量R,有了这个信息之后,如何去计算有多少个区间包含这头牛,且这头牛是孤独的且这头牛只出现一次

将所有的区间分成三大类
![[Pasted image 20240330162312.png]]

  1. 左右两边都各自至少有一个H,加上中间这个G的话,长度就大于等于3了
    可以发现,这样的话一定可以满足区间长度大于等于3,是合法的。这类区间的数量有多少个呢,左边相当于画挡板,左边有多少个H就可以画多少个挡板,右边有多少个H可以画多少种挡板,左右两边是独立的。因此这类区间的数量,就是左边H的数量乘以右边H的数量,也就是L*R,可以直接算
    ![[Pasted image 20240330162333.png]]

  2. 左边无H,右边至少有两个H,因为区间长度要大于等于3
    这类区间的数量,如果右边H的数量是R个的话,除了第一个H不能画分隔板之外,后面的每一个H都可以右边画一个分隔板,因此第二类区间的数量应该是R-1
    隔板就是指右端点
    ![[Pasted image 20240330162345.png]]

  3. 右边无H,左边至少有两个H,同理这类区间的数量是L-1

可以发现,枚举完孤独的牛之后,只需要能够快速的预处理出来左边连续的跟它不一样的牛的数量,以及每头牛右边连续的跟它不一样的牛的数量,就可以用 O ( 1 ) O(1) O(1)的时间计算出来这一列有多少个1,也就是计算出来有多少个包含这头牛且以这头牛为孤独的牛的区间的数量有多少个,这样时间复杂度 O ( n ) O(n) O(n),就可以过了

如何快速地预处理L和R,快速地计算一个字符左边有多少个连续的跟它不一样的字符

以预处理L为例,从前往后枚举,
在枚举的时候,比如孤独的牛是G的话,要看它左边连续的H的数量,如果是H的话,看它左边连续G的数量,在从前往后推的时候,只要记录一下到目前为止,连续的G的数量跟连续的H的数量就可以了,
可以动态更新

  • 如果孤独的牛是G的话,G左边连续的H的数量, S H S_{H} SH
  • 如果是H的话,左边连续G的数量就是 S G S_{G} SG
    在每次枚举的时候要动态更新一下 S H 和 S G S_{H}和S_{G} SHSG
  1. 如果枚举到H的话,表示 S H + + S_{H}++ SH++,因为这里是H,G没有,所以 S G = 0 S_{G}=0 SG=0
  2. 如果枚举到G的话, S G + + , S H = 0 S_{G}++,S_{H}=0 SG++,SH=0
    所以L是可以通过 O ( n ) O(n) O(n)的预处理算出来,
    R的话倒过来预处理就可以了,也是 O ( n ) O(n) O(n)的,这样整个算法的时间复杂度就是 O ( n ) O(n) O(n)

答案有可能爆int,因为是 N 2 N^2 N2级别

贡献法其实就是换一种枚举的角度,矩阵是为了方便理解
如果先枚举区间再枚举牛是 O ( n 2 ) O(n^2) O(n2)的,如果先枚举牛再枚举区间的话就变成 O ( n ) O(n) O(n)

代码
#include <iostream>
#include <cstring>
#include <algorithm>

typedef long long LL;

using namespace std;

const int N = 500010;

int n;
char str[N];
int l[N], r[N];

int main()
{
	//先预处理L
	scanf("%d%s", &n, str);
	//sh表示h的数量,sg表示g的数量
	for (int i = 0, sh = 0, sg = 0; i < n; i ++)
	{
		//如果发现当前是G的话
		if (str[i] == 'G')
		{
			//左边H的数量就是sh
			l[i] = sh;
			//因为这里是G
			sg ++, sh = 0;
		}
		else
		{
			l[i] = sg;
			sh ++;
			sg = 0;
		}
	}
	//枚举R的话就从后往前枚举
	for (int i = n - 1, sh = 0, sg = 0; i >= 0; i --)
	{
		if (str[i] == 'G')
		{
			r[i] = sh;
			sg ++;
			sh = 0;
		}
		else
		{
			r[i] = sg;
			sh ++;
			sg = 0;
		}
	}

	//定义一下答案
	LL res = 0;
	//枚举一下每一个牛作为一个孤独的牛,有多少个孤独区间以它为孤独的牛,res应该加上3中情况的总和
	for (int i = 0; i < n; i ++)
	{
		//这里跟0去一个max,如果右边没有的话,不能少一个,不能越加越少
		res += (LL)l[i]*r[i] + max(r[i]-1, 0) +
			max(l[i]-1, 0);
	}

	printf("%lld\n", res);
	return 0;	
}

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

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

相关文章

服务器安全事件应急响应排查方法

针对服务器操作系统的安全事件也非常多的。攻击方式主要是弱口令攻击、远程溢出攻击及其他应用漏洞攻击等。分析安全事件&#xff0c;找到入侵源&#xff0c;修复漏洞&#xff0c;总结经验&#xff0c;避免再次出现安全事件&#xff0c;以下是参考网络上文章&#xff0c;总结的…

视觉里程计之对极几何

视觉里程计之对极几何 前言 上一个章节介绍了视觉里程计关于特征点的一些内容&#xff0c;相信大家对视觉里程计关于特征的描述已经有了一定的认识。本章节给大家介绍视觉里程计另外一个概念&#xff0c;对极几何。 对极几何 对极几何是立体视觉中的几何关系&#xff0c;描…

Ruoyi-Cloud-Plus_使用Docker部署分布式微服务系统_环境准备_001---SpringCloud工作笔记200

1.首先安装docker: 如果以前安装过首先执行: yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engine 去卸载docker 2.安装dokcer需要的工具包…

校园跑腿(源码+文档)

校园跑腿管理系统&#xff08;小程序、ios、安卓都可部署&#xff09; 文件包含内容程序简要说明含有功能项目截图客户端店铺代购用户条款隐私协议租借服务行李代搬拨打客服电话注册界面我的界面申请骑手登录界面快递带取资料修改快递代寄主页万能帮 管理端代购管理添加用户订单…

Base64编码的全面介绍

title: Base64编码的全面介绍 date: 2024/3/31 18:55:49 updated: 2024/3/31 18:55:49 tags: Base64编码网络传输文本转换数据膨胀非加密性质应用场景安全传输 1. Base64的定义和作用 Base64是一种用64个字符表示二进制数据的编码方式&#xff0c;通常用于在网络传输中将二进…

SpringBoot接收参数的方式

Get 请求 1.1 以方法的形参接收参数 1.这种方式一般适用参数比较少的情况 RestController RequestMapping("/user") Slf4j public class UserController {GetMapping("/detail")public Result<User> getUserDetail(String name,String phone) {log.…

【回溯与邻里交换】纸牌三角

1.回溯算法 旋转有3种可能&#xff0c;镜像有2种 所以最后次数&#xff1a;counts/3/2 #include<iostream> using namespace std;int num[9]; int counts0; bool bools[9];//默认为false int dfs(int step){if(step9){//索引 if((num[0]num[1]num[2]num[3]num[3]num[4]n…

Docker 轻量级可视化工具 Portainer

1. 是什么 它是一款轻量级的应用&#xff0c;它提供了图形化界面&#xff0c;用于方便管理Docker环境&#xff0c;也包括单机环境和集群环境。 2. 安装 官网&#xff1a;Kubernetes and Docker Container Management Software 安装路径&#xff1a;Install the Compose plug…

微分方程数值解法_常微分方程篇

一阶常微分方程初值问题 问题的适定性 (well-posedness): (數學系的角度) • 存在性:问题有解 • 唯一性:解是唯一的 • 稳定性:这个唯一解连续地依赖于问题中所给的数据(即初值、边值等) 初值问题的求解 Euler 法 區別(極限) 入門 要點:極限、中值定理==>差分方程…

leetcode131分割回文串

递归树 下面这个代码是遍历处所有的子串 #include <bits/stdc.h> using namespace std; class Solution { public:vector<vector<string>> vvs;vector<string> vs;vector<vector<string>> partition(string s) {dfs(0,s);return vvs;}vo…

Redis持久化 RDB AOF

前言 redis的十大类型终于告一段落了,下面我们开始redis持久化新篇章 为啥需要持久化呢? 我们知道redis是挡在mysql前面的带刀侍卫 是在内存中的,假如我们的redis宕机了,难道数据直接冲入mysql??? 这显然是不可能的,mysql肯定扛不住这样的场景,所以我们有了redis持久化策略…

2014年认证杯SPSSPRO杯数学建模A题(第二阶段)轮胎的花纹全过程文档及程序

2014年认证杯SPSSPRO杯数学建模 A题 轮胎的花纹 原题再现&#xff1a; 轮胎被广泛使用在多种陆地交通工具上。根据性能的需要&#xff0c;轮胎表面常会加工出不同形状的花纹。在设计轮胎时&#xff0c;往往要针对其使用环境&#xff0c;设计出相应的花纹形状。   第二阶段问…

Django详细教程(一) - 基本操作

文章目录 前言一、安装Django二、创建项目1.终端创建项目2.Pycharm创建项目&#xff08;专业版才可以&#xff09;3.默认文件介绍 三、创建app1.app介绍2.默认文件介绍 四、快速上手1.写一个网页步骤1&#xff1a;注册app 【settings.py】步骤2&#xff1a;编写URL和视图函数对…

实战打靶集锦-029-PowerGrid

文章目录 1. 主机发现2. 端口枚举3. 服务枚举4. 服务探查4.1 探查80端口4.2 探查Dovecot imap服务4.2.1 用户爆破4.2.2 登录roundcube邮箱4.2.3 roundcube 1.2.1远程代码执行漏洞利用4.2.4 突破边界 5. 提权5.1 CVE-2019-13272漏洞利用5.2 登录p48用户5.3 内网扫描5.4 /usr/bin…

基于java+springboot+vue实现的房屋租赁系统(文末源码+Lw+ppt)23-397

摘要 随着社会的不断进步与发展&#xff0c;人们经济水平也不断的提高&#xff0c;于是对各行各业需求也越来越高。特别是从2019年新型冠状病毒爆发以来&#xff0c;利用计算机网络来处理各行业事务这一概念更深入人心&#xff0c;由于工作繁忙以及疫情的原因&#xff0c;用户…

游戏引擎中的大气和云的渲染

一、大气 首先和光线追踪类似&#xff0c;大气渲染也有类似的渲染公式&#xff0c;在实际处理中也有类似 Blinn-Phong的拟合模型。关键参数是当前点到天顶的角度和到太阳的角度 二、大气散射理论 光和介质的接触&#xff1a; Absorption 吸收Out-scattering 散射Emission …

JUC:ReentrantLock(可打断、锁超时、多条件变量)

文章目录 ReentrantLock特点基本语法可重入可打断&#xff08;避免死等、被动&#xff09;锁超时&#xff08;避免死等、主动&#xff09;公平锁多个条件变量 ReentrantLock 翻译&#xff1a;可重入锁 特点 可中断可设置超时时间&#xff08;不会一直等待锁&#xff09;可设…

关系型数据库mysql(9)主从复制和读写分离

目录 1. 主从复制和读写分离 2. mysql 支持的复制类型 3.架构图 一.主从复制 1.主从复制的定义 2.主从复制的过程 中继日志&#xff08;Relay Log&#xff09;&#xff1a; 优点&#xff1a; 3.为什么要复制 4.谁复制谁 5.数据放在什么地方 6.主从复制出现的问题 …

面向对象:多态

文章目录 一、什么是多态二、构成多态的条件2.1什么是虚函数2.1如何构成虚函数的重写&#xff08;原理层面上叫&#xff1a;覆盖&#xff09;2.2父类指针的调用 三、多态调用父类指针出现的情况四、构成多态的一种特殊情况&#xff08;协变&#xff09;五、析构函数构成的多态六…

C++AVL树拓展之红黑树原理及源码模拟

前言&#xff1a;我们之前已经从零开始掌握AVL树http://t.csdnimg.cn/LaVCChttp://t.csdnimg.cn/LaVCC 现在我们将继续学习红黑树的原理并且实现插入等功能&#xff0c;学习本章的前提要求是掌握排序二叉树和AVL树&#xff0c;本章不再提及一些基础知识&#xff0c;防止本文结…