给一个长为 的数列 ,求最多能选出几个互不相交的子段,使它们的和相等,输出方案。
只有 个区间,处理出全部的和,然后对于每个和的所有区间,求最大不重叠区间,按右端点排序的经典贪心。
/* LittleFall : Hello! */
#include <bits/stdc++.h>
using namespace std; using ll = long long; inline int read();
const int M = 1506, MOD = 1000000007;
int save[M], sum[M];
int dct[M*M], dcnt;
vector<pair<int,int>> vc[M*M];
int main(void)
{
#ifdef _LITTLEFALL_
freopen("in.txt","r",stdin);
#endif
int n = read();
for(int i=1; i<=n; ++i)
save[i] = read(), sum[i] = sum[i-1] + save[i];
for(int i=1; i<=n; ++i)
for(int j=i; j<=n; ++j)
dct[dcnt++] = sum[j]-sum[i-1];
sort(dct, dct+dcnt);
dcnt = unique(dct, dct+dcnt)-dct;
for(int i=1; i<=n; ++i)
for(int j=1; j<=i; ++j)
{
int id = lower_bound(dct, dct+dcnt, sum[i]-sum[j-1])-dct;
vc[id].push_back({j,i});
}
vector<pair<int,int>> ans;
for(int i=0; i<dcnt; ++i)
{
//求vc[i]中最多的不相交区间个数,怎么求呢?
vector<pair<int,int>> tmp;
for(int j=0; j<(int)vc[i].size(); )
{
tmp.push_back(vc[i][j]);
pair<int,int> tp = {vc[i][j].second, MOD};
while(j<(int)vc[i].size() && vc[i][j]<tp) ++j;
}
if(tmp.size()>ans.size())
ans = tmp;
}
printf("%d\n",ans.size() );
for(auto p:ans)
printf("%d %d\n",p.first,p.second );
return 0;
}
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}