前缀和前缀最大值
题目描述
运行代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
vector<int> pre(n + 1);
vector<vector<int>> sum(n + 1, vector<int>(101));
vector<int> presum(n + 1);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= 100; j++) {
sum[i][j] = sum[i - 1][j];
}
if (a[i] > 0) {
pre[i] = pre[i - 1] + 1;
} else {
pre[i] = pre[i - 1];
}
if (a[i] > 0) {
sum[i][a[i]]++;
}
presum[i] = presum[i - 1] + a[i];
}
int q;
cin >> q;
while (q--) {
int l, r;
cin >> l >> r;
int cnt = 0;
int lrsum = presum[r] - presum[l - 1];
int res = 0;
for (int i = 100; i >= 1; i--) {
int temp = sum[r][i] - sum[l - 1][i];
if (temp && lrsum > 0) {
if (lrsum - i * temp <= 0) {
cnt += (lrsum + i - 1) / i;
break;
} else {
cnt += temp;
lrsum -= i * temp;
}
}
}
int ans = pre[r] - pre[l - 1] - cnt + 1;
cout << ans << "\n";
}
return 0;
}
代码思路
一、整体思路
- 首先读取输入的整数
n
,表示序列b
的长度。 - 接着读取
n
个整数存入vector<int> a(n + 1)
(这里命名为a
,实际上代表序列b
)。 - 通过遍历序列
b
,计算并存储一些辅助信息,包括前缀和数组pre
、二维数组sum
和前缀和数组presum
。 - 然后读取整数
q
,表示询问次数。 - 对于每次询问,读取两个整数
l
和r
,表示查询区间的左右边界。在查询区间内进行计算,得到该区间序列的B
类价值并输出。
二、具体原理
-
输入输出同步和流绑定的设置
ios_base::sync_with_stdio(false);
:取消 C++ 标准流(std::cin
、std::cout
等)与 C 标准流(stdin
、stdout
等)的同步,这样可以提高输入输出的效率。cin.tie(nullptr); cout.tie(nullptr);
:解除std::cin
和std::cout
的绑定,进一步提高效率。
-
读取输入和存储序列:读取
n
后,使用循环读取n
个整数存入vector<int> a(n + 1)
。 -
计算辅助信息
- 前缀和数组
pre
:原本在给定的问题背景下不太明确其确切用途,但从代码逻辑看,可能与某些计数或统计有关,不过在这里没有完全体现出与问题中定义的AA
类价值和BB
类价值的直接联系。如果当前元素a[i]
大于 0,那么pre[i] = pre[i - 1] + 1
,否则pre[i] = pre[i - 1]
。 - 二维数组
sum
:sum[i][j]
表示前i
个元素中值为j
的元素的个数。初始化时,对于每个j
,sum[i][j] = sum[i - 1][j]
,即先继承上一个位置的值。如果当前元素a[i]
大于 0,那么sum[i][a[i]]++
。 - 前缀和数组
presum
:presum[i]
表示前i
个元素的和。通过presum[i] = presum[i - 1] + a[i]
计算得到。
- 前缀和数组
-
处理查询:对于每次查询的区间
[l, r]
:- 最后计算结果
ans = pre[r] - pre[l - 1] - cnt + 1
,并输出。然而,从给定的问题描述来看,不太清楚这个结果与问题中所求的序列b[l::r]
的B
类价值的具体对应关系。 - 然后从大到小遍历
100
到1
,对于每个值i
:- 计算区间内值为
i
的元素个数temp = sum[r][i] - sum[l - 1][i]
。 - 如果
temp
不为 0 且lrsum
大于 0,进行如下判断:- 如果
lrsum - i * temp <= 0
,说明可以用值为i
的元素以及可能更小的值的元素来填满区间,此时cnt += (lrsum + i - 1) / i
(向上取整),并跳出循环。 - 否则,用值为
i
的元素填充部分区间,cnt += temp
,同时更新lrsum
,即lrsum -= i * temp
。
- 如果
- 计算区间内值为
- 首先计算查询区间的元素和
lrsum = presum[r] - presum[l - 1]
。
- 最后计算结果
前缀平方和序列
题目描述
运行代码
#include <iostream>
#include <vector>
#define int long long
using namespace std;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
int FN(int a, int b) {
int res = 1;
while (b) {
if (b & 1) res = res * a % mod;
b >>= 1;
a = a * a % mod;
}
return res;
}
int comb(int n, int m) {
if (n < m || n < 0 || m < 0) return 0;
int res = 1;
for (int i = 1, j = n; i <= m; i++, j--) {
res = res * j % mod;
res = res *FN(i, mod - 2) % mod;
}
return res;
}
signed main() {
int n, x;
cin >> n >> x;
vector<int> p;
for (int i = 1; i * i <= x; i++)
p.push_back(i * i);
int m = p.size();
int res = comb(m, n);
cout << res <<endl;
return 0;
}
代码思路
一、整体思路
- 首先从输入中获取序列长度
n
和上限值x
。 - 找到所有不超过
x
的平方数,并存储在一个向量p
中。 - 计算从这些平方数中选取
n
个的组合数,作为满足条件的前缀平方序列的个数。
二、具体原理
-
快速幂函数
FN
部分:- 这个函数用于计算
a
的b
次幂对mod
取模的结果。 - 使用位运算的方式实现快速幂算法,当
b
的二进制表示中的某一位为1
时,将当前的a
的幂累乘到结果中,同时不断更新a
为a
的平方,b
右移一位,直到b
变为0
。
- 这个函数用于计算
-
组合数计算函数
comb
部分:- 这个函数用于计算从
n
个不同元素中选取m
个的组合数。 - 首先判断输入的合法性,如果
n < m
或者n
、m
为负数,则返回0
。 - 然后通过递推的方式计算组合数,先将
n
开始的m
个数累乘到结果中,同时对于每一步乘积,都乘以当前步数的逆元(即FN(i, mod - 2)
,利用费马小定理计算逆元),最后得到组合数对mod
取模的结果。
- 这个函数用于计算从
-
主函数部分:
- 读取输入的
n
和x
。 - 通过遍历找到所有不超过
x
的平方数,并存储在向量p
中,其大小为m
。 - 调用
comb
函数计算从m
个平方数中选取n
个的组合数,作为满足条件的前缀平方序列的个数,并输出结果。
- 读取输入的
总的来说,这个算法的原理是通过计算不超过给定上限 x
的平方数的组合数,来确定满足长度为 n
且前缀和都是平方数且不超过 x
的序列的个数。因为满足条件的序列的前缀和必须是不超过 x
的平方数,所以可以先找出这些平方数,然后计算从这些平方数中选取 n
个的组合数,即为所求的结果。
好数组
题目描述
运行代码
#include <iostream>
int main() {
int n;
std::cin >> n;
for (int i = 0; i < n; ++i) {
int x;
std::cin >> x;
if (x == 0) {
std::cout << "NO";
return 0;
}
}
std::cout << "YES";
return 0;
}
代码思路
一、整体思路
- 首先从输入中获取数组的长度
n
。 - 然后依次读取
n
个整数作为数组的元素。 - 在读取过程中检查是否存在元素为
0
,如果有则直接输出"NO"
并结束程序。 - 如果所有元素都不为
0
,则输出"YES"
。
二、具体原理
-
输入数据部分:使用
std::cin >> n
读取数组的长度n
。接着使用一个循环,每次读取一个整数x
,代表数组中的一个元素。 -
检查元素部分:在循环中,检查每个读取的元素
x
是否为0
。如果某个元素为0
,根据题目要求,存在两个相同的元素(都是0
),它们的差的绝对值为0
,而乘积也为0
,不满足 “任意两个元素的差的绝对值都小于这两个元素的乘积” 这个条件,所以输出"NO"
并返回。 -
输出结果部分:如果循环结束后都没有发现元素为
0
,说明可能满足好数组的条件,输出"YES"
。
这个代码的原理是通过逐个检查输入数组中的元素是否为 0
,来快速判断是否不满足好数组的条件。如果没有找到 0
元素,就假设可能满足好数组的条件并输出 "YES"
。