【ACM算法竞赛日常训练】DAY16【奇♂妙拆分】【区区区间间间】【小AA的数列】数学 | 位运算 | 前缀和
DAY16共3题:
奇♂妙拆分(简单数学)
区区区间间间(单调栈)
小AA的数列(位运算dp)
作者:Eriktse
简介:19岁,211计算机在读,现役ACM银牌选手力争以通俗易懂的方式讲解算法!️欢迎关注我,一起交流C++/Python算法。(优质好文持续更新中……)
阅读原文获得更好阅读体验:https://www.eriktse.com/algorithm/1119.html
奇♂妙拆分(简单数学)
根据贪心的想法,若要使得因子尽可能多,那么因子应当尽可能小,大于根号n的因子至多一个,从小到大枚举[1, sqrt(n)]的所有整数,如果i能够整除n就作为一个因子。
Code:
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve()
{
int n;cin >> n;
set<int> st;
for(int i = 1;i <= n / i; ++ i)
if(n % i == 0)st.insert(i), n /= i;
st.insert(n);
cout << st.size() << '\n';
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _;cin >> _;
while(_ --)solve();
return 0;
}
区区区间间间(单调栈)
题意:给定一个数组,求所有子区间的最大值与最小值的差的和。
如果暴力枚举肯定不行,单单是子区间个数就有n ^ 2个,所以我们应该考虑每一个元素对答案的贡献,也就是说我们需要知道某个元素a[i]它会在多少个区间里作为最大值,在多少个区间里作为最小值。
我们预处理出四个数组,分别是lmax[], rmax[], lmin[], rmin[]表示点i作为最大值的左右最远位置,和作为最小值的左右最远位置(lmax[i] = j,表示在区间[j, i]中的最大值都是a[i],其他的三个数组类似定义)。
用单调栈可以处理出这四个数组,一下以求lmax[]举例,维护一个单调不增栈,栈内存放的是下标。
初始时栈内仅有一个a[0] = inf。
当我们遇到一个a[i]时,不断地判断栈顶元素,如果栈顶元素比a[i]小,说明这个栈顶应当弹出。
当更新完毕后,此时的栈顶的右边相邻位置就是a[i]往左的最远的位置了,因为此时栈顶是a[i]往左的第一个大于等于a[i]的位置,那么这中间的元素都会小于a[i]。
其他的三个数组类似,注意,如果我们处理lmax用的是单调不增栈,那么处理rmax就应当用单调递增栈,而不是单调不减栈,否则可能出现区间重复表示或没有归属的问题(自己思考)。
Code:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 9, inf =8e18;
int a[N], stk[N], top, lmax[N], rmax[N], lmin[N], rmin[N];
void solve()
{
int n;cin >> n;
for(int i = 1;i <= n; ++ i)cin >> a[i];
a[0] = a[n + 1] = inf;
top = 0;
stk[++ top] = 0;
for(int i = 1;i <= n; ++ i)
{
while(top && a[i] > a[stk[top]])top --;
lmax[i] = stk[top] + 1;
stk[++ top] = i;
}
top = 0;
stk[++ top] = n + 1;
for(int i = n;i >= 1; -- i)
{
while(top && a[i] >= a[stk[top]])top --;
rmax[i] = stk[top] - 1;
stk[++ top] = i;
}
a[0] = a[n + 1] = -inf;
top = 0;
stk[++ top] = 0;
for(int i = 1;i <= n; ++ i)
{
while(top && a[i] < a[stk[top]])top --;
lmin[i] = stk[top] + 1;
stk[++ top] = i;
}
top = 0;
stk[++ top] = n + 1;
for(int i = n;i >= 1; -- i)
{
while(top && a[i] <= a[stk[top]])top --;
rmin[i] = stk[top] - 1;
stk[++ top] = i;
}
int ans = 0;
for(int i = 1;i <= n; ++ i)
{
ans += a[i] * (rmax[i] - i + 1) * (i - lmax[i] + 1);
ans -= a[i] * (rmin[i] - i + 1) * (i - lmin[i] + 1);
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _;cin >> _;
while(_ --)solve();
return 0;
}
小AA的数列(位运算 | 前缀和)
这道题一看有点懵,感觉不是很好处理,但依然是套路题。
看到异或,我们应该想把每一个二进制位拆分开,实际上这里约32位二进制位可以先认为是相互独立的,对于每一位都计算出贡献,然后按照位权重加和即可。
异或题的套路基本都是拆分二进制,整体考虑起来比较复杂,拆分后会简单很多。
先不管L, R。
假如我们考虑数组1 2 3 4 5的第0位:
获取第0位后得到b数组:1 0 1 0 1。
因为我们要得到区间内1的个数,所以处理一个异或前缀和p[]是自然而然的,然后我们枚举每一位作为左端点,看看会得到一个怎样的式子:
\]
我们知道异或其实就是% 2的加法,也是% 2减法,所以我们将异或前缀和改为普通前缀和p[],以上的柿子可以转化为:
\]
那么我们就可以对p再做一个前缀和p2,但是p2的步长应为2。
然后上面的柿子就等价于(其中l, r为j的上下限,需要保证与i - 1奇偶性相同,j的个数为(r - l + 2) / 2):
\]
因为这个p2存在p2[-1]的情况,所以我们做个小小的便宜,方便代码的编写(其实你想要特判也行,只是不太方便,也容易出错)。
注意一下其他细节即可。
Code:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 109, p = 1e9 + 7, T = 100;
int a[N], b[N], p1[N], p2[N];
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, l, r;cin >> n >> l >> r;
for(int i = 1;i <= n; ++ i)cin >> a[i];
int ans = 0;
for(int w = 0;w <= 32; ++ w)
{
for(int i = 1;i <= n; ++ i)b[i] = a[i] >> w & 1;
for(int i = 1;i <= n; ++ i)p1[T + i] = (b[i] + p1[T + i - 1]) % 2;
for(int i = 1;i <= n; ++ i)p2[T + i] = p1[T + i] + p2[T + i - 2];
int sum = 0;
for(int i = 1;i <= n; ++ i)
{
int j1 = max(i + 1, l + i - 1), j2 = min(n, r + i - 1);
if((j1 - i) % 2 == 0)j1 ++;
if((j2 - i) % 2 == 0)j2 --;
if(j2 < j1)continue;
sum += abs(p2[T + j2] - p2[T + j1 - 2] -
p1[T + i - 1] * ((j2 - j1) / 2 + 1));
}
ans = (ans + (1ll << w) * sum % p) % p;
}
cout << ans << '\n';
return 0;
}
本文由eriktse原创,创作不易,如果对您有帮助,欢迎小伙伴们点赞、收藏、留言
【ACM算法竞赛日常训练】DAY16【奇♂妙拆分】【区区区间间间】【小AA的数列】数学 | 位运算 | 前缀和的更多相关文章
- 【经验总结】Java在ACM算法竞赛编程中易错点
一.Java之ACM易错点 1. 类名称必须采用public class Main方式命名 2. 在有些OJ系统上,即便是输出的末尾多了一个“ ”,程序可能会输出错误,所以在我看来好多OJ系统做的是非 ...
- ACM算法竞赛:抄课文
题目如下: 比如现在要写一句话 Hello world 输入: n (n > 0) 比如输入的n为10,就将Hello world打印十 #include <stdio.h> #in ...
- hihocoder Round #c1(hihoCoder太阁最新面经算法竞赛1 )
Test链接:https://cn.vjudge.net/contest/231849 选自hihoCoder太阁最新面经算法竞赛1 更多Test:传送门 A:区间求差 给一组区间集合A和区间集合B, ...
- 算法竞赛入门经典训练指南——UVA 11300 preading the Wealth
A Communist regime is trying to redistribute wealth in a village. They have have decided to sit ever ...
- 华南师大 2017 年 ACM 程序设计竞赛新生初赛题解
题解 被你们虐了千百遍的题目和 OJ 也很累的,也想要休息,所以你们别想了,行行好放过它们,我们来看题解吧... A. 诡异的计数法 Description cgy 太喜欢质数了以至于他计数也需要用质 ...
- Aho-Corasick automaton(AC自动机)解析及其在算法竞赛中的典型应用举例
摘要: 本文主要讲述了AC自动机的基本思想和实现原理,如何构造AC自动机,着重讲解AC自动机在算法竞赛中的一些典型应用. 什么是AC自动机? 如何构造一个AC自动机? AC自动机在算法竞赛中的典型应用 ...
- ACM算法锦集
一:知识点 数据结构: 1,单,双链表及循环链表 2,树的表示与存储,二叉树(概念,遍历)二叉树的 应用(二叉排序树,判定树,博弈树,解答树等) 3,文件操作(从文本文件中读入数据并输出到文本文 件中 ...
- (Step1-500题)UVaOJ+算法竞赛入门经典+挑战编程+USACO
http://www.cnblogs.com/sxiszero/p/3618737.html 下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年 ...
- [刷题]算法竞赛入门经典 3-10/UVa1587 3-11/UVa1588
书上具体所有题目:http://pan.baidu.com/s/1hssH0KO 题目:算法竞赛入门经典 3-10/UVa1587:Box 代码: //UVa1587 - Box #include&l ...
- 算法竞赛入门经典+挑战编程+USACO
下面给出的题目共计560道,去掉重复的也有近500题,作为ACMer Training Step1,用1年到1年半年时间完成.打牢基础,厚积薄发. 一.UVaOJ http://uva.onlinej ...
随机推荐
- css 多行文本展开收起
<template> <div class="content"> <div :class="[isOpen ? 'text' : 'text ...
- go写文件常用方法
注意:打开文件,一定记得关闭 file, err := os.OpenFile(name, flag, perm) defer file.Close() 一.打开文件|创建 1.os.OpenFile ...
- Rfost的自我介绍+软工五问
自我介绍+软工五问 问题 解答 这个作业属于哪个课程 网工1934-软件工程 这个作业要求在哪里 作业要求 这个作业的目标 让学生对软件工程有个初步的了解,同时掌握基础的markdown语法和博客园的 ...
- C# DevExpress gridview 字符串尾部带数字如何排序
我们经常遇到这样的问题,字符串尾部带数字,如何正确排序; 首先设置GridView ,Columns 的相关列,设置属性中,SortMode为Custom 解决思路,把字符串尾缀数字,分离出来.先比较 ...
- 2020/513-笔记:怎么知道Oracle数据库一个中文汉字占几个字节
1. 执行语句: select userenv('language') from dual; 如果显示如下: SIMPLIFIED CHINESE_CH ...
- 深入理解css 笔记(6)
网格布局:flexbox 彻底改变了网页布局方式,但这只是开始.它还有一个大哥:另一个称作网格布局模块的新规范.这两个规范提供了一种前所未有的全功能布局引擎.跟 flexbox 类似,网格布局也是作用 ...
- .net core 版本避坑 无法打开项目文件。 无法找到 .NET SDK。请检查确保已安装此项且 global.json 中指定的版本(如有)与所安装的版本相匹配。
打开项目根目录,输入 dotnet --version ,查看本机安装的最高版本的sdk: 如果源文件中存在global.json文件,直接打开修改即可: 不存在则接着在1步骤后输入: dotnet ...
- 本地插件文件导入cordova 项目中
cordova plugin add F:\ucc\android\cordova-plugin-datepicker add 后面是插件文件的本地地址
- DB2通过java代码生成自定义uuid()函数
一.简单的方法 此种方法在快速大量生成时,会有重复 SELECT concat (hex (RAND ()), hex (RAND ())) as uuid FROM SYSIBM.SYSDUMMY1 ...
- nginx 代理路径
反向代理被代理url没有截取 /report/api/ /report/api/bussinessRisk/zhucai/creditInquiry 应该是/bussinessRisk/zhucai/ ...