长序列
解题思路
问题分析:
题目给出了一个长度为N的序列A,将其重复连接10^100次得到序列B。要求找出最小的k,使得B的前k项之和首次超过给定的X值。
关键观察:
- 由于B是A的无限循环,我们可以利用周期性来优化计算。
- 首先计算一个完整周期(即整个A序列)的和S = sum(A)。
- 计算完整的周期数m = X // S,这部分贡献了m * N个元素。
- 剩下的余数X % S需要在当前周期内找到最小的k2,使得前k2项之和超过这个余数。
- 最终答案就是m * N + k2。
优化点:
- 使用前缀和数组s[]来快速计算部分和。
- 通过模运算减少不必要的重复计算。
代码注释
#include<bits/stdc++.h>
using namespace std;
#define ll long long // 定义long long类型别名
const int N = 1e5+5; // 定义数组最大长度
ll n, x; // n-序列长度,x-目标和
ll a[N], s[N]; // a-原始序列,s-前缀和数组
int main() {
// 输入序列长度n
cin>>n;
// 输入序列并计算前缀和
for(int i=1;i<=n;i++){
cin>>a[i];
s[i] = s[i-1] + a[i]; // s[i]表示前i项的和
}
// 输入目标和x
cin>>x;
// 计算完整周期的贡献
// k = 完整周期数 * 每个周期的元素数
ll k = x/s[n] * n;
// 计算剩余部分
x %= s[n];
// 在当前周期内寻找最小的k2使得和超过x
int k2= 0;
for(int i=1;i<=n;i++){
if(s[i]>x){ // 当部分和超过剩余x时
k2 = i; // 记录位置
break; // 找到后立即退出
}
}
// 总元素数 = 完整周期贡献 + 当前周期内需要的元素数
k += k2;
// 输出结果
cout<<k;
return 0;
}
代码解释
-
输入处理:
- 读取序列长度n
- 读取序列元素并同时计算前缀和数组s[]
-
周期计算:
k = x/s[n] * n
计算完整周期贡献的元素数量x %= s[n]
计算剩余需要处理的部分和
-
剩余部分处理:
- 遍历前缀和数组,找到第一个超过剩余x的位置k2
-
结果输出:
- 将完整周期贡献和剩余部分贡献相加得到最终结果k
该算法的时间复杂度为O(N),能够高效处理题目给出的最大约束条件(N ≤ 1e5)。通过利用周期性性质和前缀和优化,避免了不必要的重复计算。