问题描述
小M拥有一个长度为n的数组,该数组会每秒发生一次变幻。具体规则是:每次变幻,数组的第1个位置的数字与第2个位置的数字合并,数组的第3个位置的数字与第4个位置的数字合并,依次类推,直到只剩下两个数字为止。合并的规则是将两个数字相加。
小M希望知道数组在每次变幻后,数组的第一个数字会累加到一个初始值为0的变量x中,最后输出变量x的值。由于数据量可能非常大,最后的答案需要对 10^9+7 取模。
为了简化输入,数组是通过k条信息给出的,信息的形式为两个数组 a
和 b
,其中 a[i]
表示数组中有 a[i]
个数字 b[i]
。
测试样例
样例1:
输入:
n = 5 ,k = 5,a = [1, 1, 1, 1, 1] ,b = [1, 2, 3, 4, 5]
输出:13
样例2:
输入:
n = 7 ,k = 2,a = [3, 4] ,b = [1, 2]
输出:7
样例3:
输入:
n = 10 ,k = 2,a = [3, 7] ,b = [1, 2]
输出:20
Python解题
思路说明
题目要求模拟一个数组每秒的变幻过程,每次变幻将相邻的两个数字合并,直到数组中只剩下两个数字为止。每次变幻后,数组的第一个数字会被累加到一个初始值为0的变量x中,最后输出变量x的值。由于数据量可能非常大,最后的答案需要对 109+7 取模。
为了简化输入,数组是通过k条信息给出的,信息的形式为两个数组 a
和 b
,其中 a[i]
表示数组中有 a[i]
个数字 b[i]
。
我们可以使用队列来模拟这个过程,每次从队列中取出两个数字进行合并,并将结果重新放回队列中。每次合并后,累加第一个数字到结果中,并继续进行下一次合并,直到队列中只剩下两个数字为止。
解题过程
- 初始化队列:将输入的
a
和b
数组转换为队列q
,其中每个元素是一个元组(count, value)
,表示有count
个value
。 - 模拟合并过程:
- 使用
ok
函数判断队列中是否还有超过两个数字。 - 每次从队列中取出两个数字进行合并,并将结果重新放回队列中。
- 如果队列中只剩下一个数字,直接将其放回队列中。
- 每次合并后,累加第一个数字到结果
ans
中。
- 使用
- 取模操作:由于数据量可能非常大,每次累加后需要对 109+7 取模。
- 返回结果:最终返回累加的结果
ans
。
复杂度分析
- 时间复杂度:每次合并操作的时间复杂度为 O(1),总共需要进行 O(n) 次合并操作,因此总的时间复杂度为 O(n)。
- 空间复杂度:使用了一个队列来存储数组元素,队列的最大长度为 O(n),因此空间复杂度为 O(n)。
知识点扩展
- 队列数据结构:队列是一种先进先出(FIFO)的数据结构,适合用于模拟需要按顺序处理的问题。
- 模拟算法:模拟算法通过模拟问题的实际过程来解决问题,适合用于处理需要逐步操作的问题。
- 取模运算:在处理大数问题时,取模运算可以防止结果溢出,保证结果在合理范围内。
代码实现
def solution(n: int, k: int, a: list, b: list) -> int:
assert k == len(a)
assert k == len(b)
assert n == sum(a)
def ok(v):
t = 0
for x, y in v:
t += x
if t > 2:
return True
return False
q = []
for x, y in zip(a, b):
q.append((x, y))
mod = int(1e9 + 7)
ans = 0
while ok(q):
q2 = []
while q:
if q[0][0] == 0:
q.pop(0)
elif q[0][0] == 1:
if len(q) >= 2:
q[1] = (q[1][0] - 1, q[1][1])
q2.append((1, (q[0][1] + q[1][1]) % mod))
else:
q2.append((1, q[0][1]))
q.pop(0)
else:
q2.append((q[0][0] >> 1, (q[0][1] << 1) % mod))
q[0] = (q[0][0] & 1, q[0][1])
ans = (ans + q2[0][1]) % mod
q = q2
return ans
if __name__ == '__main__':
print(solution(n = 5 ,k = 5,a = [1, 1, 1, 1, 1] ,b = [1, 2, 3, 4, 5]) == 13)
print(solution(n = 7 ,k = 2,a = [3, 4] ,b = [1, 2]) == 7)
print(solution(n = 10 ,k = 2,a = [3, 7] ,b = [1, 2]) == 20)
C++解题
问题理解
-
数组变幻规则:
- 每秒数组的第1个位置的数字与第2个位置的数字合并,第3个位置的数字与第4个位置的数字合并,依次类推。
- 合并的规则是将两个数字相加。
- 这个过程会一直持续,直到数组中只剩下两个数字为止。
-
累加规则:
- 每次变幻后,数组的第一个数字会累加到一个初始值为0的变量x中。
- 最终输出变量x的值,并且需要对 109+7 取模。
-
输入格式:
- 数组是通过k条信息给出的,信息的形式为两个数组
a
和b
。 a[i]
表示数组中有a[i]
个数字b[i]
。
- 数组是通过k条信息给出的,信息的形式为两个数组
代码实现
#include <iostream>
#include <vector>
#include <queue>
#include <assert.h>
#include <numeric>
using namespace std;
const int MOD = 1e9 + 7;
int solution(int n, int k, vector<int> a, vector<int> b) {
assert(k == a.size());
assert(k == b.size());
assert(n == accumulate(a.begin(), a.end(), 0));
auto ok = [](const vector<pair<int, int>>& v) {
int t = 0;
for (const auto& [x, y] : v) {
t += x;
if (t > 2) return true;
}
return false;
};
vector<pair<int, int>> q;
for (int i = 0; i < k; ++i) {
q.emplace_back(a[i], b[i]);
}
int ans = 0;
while (ok(q)) {
vector<pair<int, int>> q2;
while (!q.empty()) {
if (q[0].first == 0) {
q.erase(q.begin());
} else if (q[0].first == 1) {
if (q.size() >= 2) {
q[1].first -= 1;
q2.emplace_back(1, (q[0].second + q[1].second) % MOD);
} else {
q2.emplace_back(1, q[0].second);
}
q.erase(q.begin());
} else {
q2.emplace_back(q[0].first >> 1, (q[0].second << 1) % MOD);
q[0].first &= 1;
}
}
ans = (ans + q2[0].second) % MOD;
q = move(q2);
}
return ans;
}
int main() {
cout << (solution(5, 5, {1, 1, 1, 1, 1}, {1, 2, 3, 4, 5}) == 13) << endl;
cout << (solution(7, 2, {3, 4}, {1, 2}) == 7) << endl;
cout << (solution(10, 2, {3, 7}, {1, 2}) == 20) << endl;
return 0;
}