DLUTOJ 1331 Maximum Sum

传送门

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\n", 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\n", ans);
    }
    return 0;
}

写这道题主要是复习C++ STL。上面提到的查询也可以用划分树来写,不过麻烦了许多。BST又不会敲,sigh。。。。。

posted @ 2016-04-14 19:05  Pat  阅读(456)  评论(0编辑  收藏  举报