Time Limit: 1 Sec Memory Limit: 128 MB
Description
You are given an array of size N and another integer M.Your target is to find the maximum value of sum of subarray modulo M.
Subarray is a continous subset of array elements.
Note that we need to find the maximum value of (Sum of Subarray)%M , where there are N*(N+1)/2 possible subarrays.
Input
First line contains T , number of test cases to follow. Each test case consits of exactly 2 lines. First line of each test case contain 2 space separated integers N and M, size of the array and modulo value M.
Second line contains N space separated integers representing the elements of the array.
2 ≤ N ≤ 10^5
1 ≤ M ≤ 10^14
1 ≤ elements of the array ≤ 10^18
2 ≤ Sum of N over all test cases ≤ 500000
Output
For every test case output the maximum value asked above in a newline.
Sample Input
1 5 7 3 3 9 9 5
Sample Output
6
HINT
Max Possible Sum taking Modulo 7 is 6 , and we can get 6 by adding first and second element of the array
Source
Solution:
$先预处理出数组在模M下的前缀和sum[ ].$
$枚举区间起点L,然后在sum[L+1, ..., n]上查找两个值:$
[v_1=max{sum[i]: sum[i] < sum[L]}]
[v_2=max{sum[i]: sum[i] ge sum[L]}]
然后用
[max(v_{1}-a[L]+M, v_{2}-a[L])]
更新答案
Implementation:可以用map,也可以用multiset.
map版
忘了map自带lower_bound函数,而且只能用这个lower_bound,不能写成lower_bound(b, e, k)
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N(1e5+5); map<LL,int> mp; int n; LL m, a[N]; map<LL,int>::iterator it; int main(){ int T; for(scanf("%d", &T); T--; ){ scanf("%d%lld", &n, &m); mp.clear(); for(int i=1; i<=n; i++) scanf("%lld", a+i), a[i]+=a[i-1], a[i]%=m, mp[a[i]]++; mp[0]++; LL ans=0; for(int i=0; i<n; i++){ mp[a[i]]--; if(!mp[a[i]]) mp.erase(a[i]); ans=max(ans, ((--mp.end())->first-a[i]+m)%m); it=mp.lower_bound(a[i]); if(it!=mp.begin()) ans=max(ans, (--it)->first-a[i]+m); } printf("%lld ", ans); } return 0; }
multiset 版
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N(1e5+5); multiset<LL> ms; int n; LL m, a[N]; multiset<LL>::iterator it; int main(){ int T; for(scanf("%d", &T); T--; ){ scanf("%d%lld", &n, &m); ms.clear(); for(int i=1; i<=n; i++) scanf("%lld", a+i), a[i]+=a[i-1], a[i]%=m, ms.insert(a[i]); ms.insert(0); LL ans=0; for(int i=0; i<n; i++){ it=ms.find(a[i]); ms.erase(it); ans=max(ans, (*--ms.end()-a[i]+m)%m); it=ms.lower_bound(a[i]); if(it!=ms.begin()) ans=max(ans, *--it-a[i]+m); } printf("%lld ", ans); } return 0; }
写这道题主要是复习C++ STL。上面提到的查询也可以用划分树来写,不过麻烦了许多。BST又不会敲,sigh。。。。。