Codeforces Round #547 (Div. 3) cf 1141 F1/F2 . Same Sum Blocks (Hard)

F2. Same Sum Blocks (Hard)

time limit per test

3 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

This problem is given in two editions, which differ exclusively in the constraints on the number nn.

You are given an array of integers a[1],a[2],…,a[n].a[1],a[2],…,a[n]. A block is a sequence of contiguous (consecutive) elements a[l],a[l+1],…,a[r]a[l],a[l+1],…,a[r] (1≤l≤r≤n1≤l≤r≤n). Thus, a block is defined by a pair of indices (l,r)(l,r).

Find a set of blocks (l1,r1),(l2,r2),…,(lk,rk)(l1,r1),(l2,r2),…,(lk,rk) such that:

  • They do not intersect (i.e. they are disjoint). Formally, for each pair of blocks (li,ri)(li,ri) and (lj,rj(lj,rj) where i≠ji≠j either ri<ljri<lj or rj<lirj<li.
  • For each block the sum of its elements is the same. Formally,

    a[l1]+a[l1+1]+⋯+a[r1]=a[l2]+a[l2+1]+⋯+a[r2]=a[l1]+a[l1+1]+⋯+a[r1]=a[l2]+a[l2+1]+⋯+a[r2]=

    ⋯=⋯=

    a[lk]+a[lk+1]+⋯+a[rk].a[lk]+a[lk+1]+⋯+a[rk].

  • The number of the blocks in the set is maximum. Formally, there does not exist a set of blocks (l′1,r′1),(l′2,r′2),…,(l′k′,r′k′)(l1′,r1′),(l2′,r2′),…,(lk′′,rk′′)satisfying the above two requirements with k′>kk′>k.

The picture corresponds to the first example. Blue boxes illustrate blocks.

Write a program to find such a set of blocks.

Input

The first line contains integer nn (1≤n≤15001≤n≤1500) — the length of the given array. The second line contains the sequence of elements a[1],a[2],…,a[n]a[1],a[2],…,a[n] (−105≤ai≤105−105≤ai≤105).

Output

In the first line print the integer kk (1≤k≤n1≤k≤n). The following kk lines should contain blocks, one per line. In each line print a pair of indices li,rili,ri (1≤li≤ri≤n1≤li≤ri≤n) — the bounds of the ii-th block. You can print blocks in any order. If there are multiple answers, print any of them.

Examples

input

Copy

7
4 1 2 2 1 5 3

output

Copy

3
7 7
2 3
4 5

input

Copy

11
-5 -4 -3 -2 -1 0 1 2 3 4 5

output

Copy

2
3 4
1 1

input

Copy

4
1 1 1 1

output

Copy

4
4 4
1 1
2 2
3 3

n个数,找出来不相交的一些区间,使得这些区间的和相同,求这些区间最多是多少,并且输出 

显然直接枚举区间,然后map一下存在vector里,对于每个sum里的vector排序,类似最多不相交线段区间最多的个数,直接贪心就可以,最后记录ans

#include <bits/stdc++.h>
#include <time.h>
#define fi first
#define se second

using namespace std;

typedef long long ll;
typedef double db;
int xx[4] = {1,-1,0,0};
int yy[4] = {0,0,1,-1};
const double eps = 1e-9;
typedef pair<int,int>  P;
const int maxn = 1e6;
const ll mod = 1e9 + 7; 
ll c,n,k;
int  a[maxn],ss[maxn];
map<int,int>m;
ll vis[maxn];
vector<P>v[maxn];
bool cmp(P a,P b){
    if(a.second == b.second) return a.first < b.first;
        return a.second < b.second;
}
int main() {
    ios::sync_with_stdio(false);
    while(cin >> n){
        for(int i = 1;i <= n;i++) cin >> a[i];
        int cnt = 1;
        for(int i = 1;i <= n;i++) ss[i] = ss[i - 1] + a[i];
        set<int>s;
        for(int i = 1;i <= n;i++){
            for(int j = i;j <= n;j++){
                int x = ss[j] - ss[i - 1];
                if(!m[x]) m[x] = cnt++;
                v[m[x]].push_back(P(i,j));
                s.insert(x);
            }
        }
        vector<P>ans,cur;
        for(auto d:s){
            sort(v[m[d]].begin(),v[m[d]].end(),cmp);
            int flag = 0,l = 0,r = 0;
            cur.clear();
            for(auto dd:v[m[d]]){
                if(!flag){
                    cur.push_back(dd);l = dd.first ,r = dd.second;
                    flag = 1;
                }else{
                    if(r == dd.second) continue;
                    if(dd.first > r){
                        l = dd.first,r = dd.second;
                        cur.push_back(dd);
                    }
                }
            }
                if(cur.size() > ans.size()) ans = cur;
        }
        cout << ans.size() << endl;
        for(auto d:ans){
            cout << d.fi << " " << d.se << endl;
        }
    }
    cerr << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}





 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值