给定一个数组 A = a0,a1,... a ,大小最大为N≤10^ 5 ,0≤a我≤10^ 9。
数字 0< M≤10^ 9。
任务是找到最大值Σ(k = i,j)a k %M =(a i + a i + 1 + a (i + 2) +⋯+ a (j-1) + a (j))%M ,以及有多少不同的范围(i,j)得到这笔款项。
复杂性必须小于 O(N ^ 2),后者太慢。
N = 3, M = 5
A = {2,4,3}
最大总和模式M 4 且 2 范围, a 0 到 2 和 a 1
让我们定义 s [j] =(a 0 + a 1 + ... + a j )%M 所以如果你想要以 j 结尾的最佳总和,你必须选择 s [i] i< j s [i]是比你高的最小金额。
因为如果 s [i]> S [J]。 s [i] = M - K; K< M - s [j] 那么结果和范围将是(s [j] -s [i] + M)%M =(s [j] + K)%M 因为 K< M - s [j] 它会增加结果 mod M ,并且当 s [j] 更接近 s [j] 它会增加结果 mod M 。
答案 0 :(得分:0)
这个想法是我的尝试,首先你必须要计算从0开始并以索引i结束的所有总和,然后你可以通过二进制搜索搜索值来搜索比你快的更小的值。地图已经有(lower_bound),并计算您可以与找到的值相加的时间。你必须把钱保留在某个地方,以计算你可以做多少时间。
#include <iostream>
#include <map>
#define optimizar_io ios_base::sync_with_stdio(false);cin.tie(NULL);
using namespace std;
const int LN = 1e5;
long long N, M, num[LN];
map < long long, int > sum;
int main() {
optimizar_io
cin >> N >> M;
sum[0]++;
long long cont = 0, tmax = 0, res = 1, val;
map < long long, int > :: iterator best;
for (int i = 0; i < N; i++)
{
cin >> num[i];
cont = (cont + num[i]) % M;
if (tmax == cont)
res += sum[0];
if (tmax < cont)
tmax = cont, res = sum[0];
best = sum.lower_bound(cont + 1);
if (best != sum.end())
{
val = cont - (*best).first + M;
if (tmax == val)
res += (*best).second;
if (tmax < val)
tmax = val, res = (*best).second;
}
sum[cont]++;
}
cout << tmax << " " << res;
return 0;
}