题意
给出n个数,求一个区间[l,r],使得(a[l]+a[l+1]+…+a[r]) mod m 最大。
n<=200000,m<=1018
分析
考虑前缀和sum,若[l,r]为最优解,必然(sum[r]-sum[l-1]) mod m 最大,那么必然有sum[l-1]>sum[r]且sum[l-1]最小。
用平衡树动态维护后继即可。
网上貌似都是敲set,像我这种手打平衡树的估计不多了。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<ctime>
#define ll long long
#define N 200005
using namespace std;
int n,root,tot;
ll a[N],m;
struct treap{int l,r,k;ll val;}t[N];
void rttl(int &x)
{
int y=t[x].r;
t[x].r=t[y].l;
t[y].l=x;
x=y;
}
void rttr(int &x)
{
int y=t[x].l;
t[x].l=t[y].r;
t[y].r=x;
x=y;
}
void ins(int &d,ll x)
{
if (!d)
{
d=++tot;t[tot].val=x;t[tot].k=rand();
return;
}
if (x==t[d].val) return;
if (x<t[d].val)
{
ins(t[d].l,x);
if (t[t[d].l].k<t[d].k) rttr(d);
}else
{
ins(t[d].r,x);
if (t[t[d].r].k<t[d].k) rttl(d);
}
}
ll find(ll w)
{
int x=root;
ll y=0;
while (x)
if (t[x].val>w)
{
y=t[x].val;
x=t[x].l;
}
else x=t[x].r;
return y;
}
int main()
{
scanf("%d%lld",&n,&m);
ll ans=0;
for (int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
a[i]=(a[i]%m+m)%m;
a[i]=(a[i-1]+a[i])%m;
ans=max(ans,a[i]);
}
for (int i=1;i<=n;i++)
{
ll x=find(a[i]);
if (x) ans=max(ans,((a[i]-x)%m+m)%m);
ins(root,a[i]);
}
printf("%lld",ans);
return 0;
}