http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1002&cid=886
这个榜歪到天上去了,LCT过120队,这题线段树裸题过30+队
这题就是dp[i]只能从dp[i-R]---dp[i-L]这段转移过来,那么对前缀和离散化一下,把前缀和当下标维护一棵权值线段树,记录区间段最大的dp值,注意这题由于可能有重复的前缀和,所以不要unique,就是排序然后就可以让一个位置的sum[i]确定一个下标,就不用考虑重复的问题了。
然后转移的时候就分3中情况,sum[i]-sum[j]<0,=0,>0,lower_bound,upper_bound搞搞看从线段树哪个区间的最大值转移过来。
i向后移,就把i-R从权值线段树中删了,把i-L+1加进权值线段树
#include<bits/stdc++.h>
namespace FastIO {
const int SIZE = 1 << 16;
char buf[SIZE], obuf[SIZE], str[60];
int bi = SIZE, bn = SIZE, opt;
int read(char *s) {
while (bn) {
for (; bi < bn && buf[bi] <= ' '; bi++);
if (bi < bn) break;
bn = fread(buf, 1, SIZE, stdin);
bi = 0;
}
int sn = 0;
while (bn) {
for (; bi < bn && buf[bi] > ' '; bi++) s[sn++] = buf[bi];
if (bi < bn) break;
bn = fread(buf, 1, SIZE, stdin);
bi = 0;
}
s[sn] = 0;
return sn;
}
bool rd(int& x) {
int n = read(str), bf;
if (!n) return 0;
int i = 0; if (str[i] == '-') bf = -1, i++; else bf = 1;
for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
if (bf < 0) x = -x;
return 1;
}
};
using namespace FastIO;
using namespace std;
const int maxl=2e6+10;
const int inf=2e9+10;
int n,L,R,cnt,tot;
int a[maxl],c[maxl],sum[maxl],dp[maxl];
int id[maxl];
struct ind
{
int val,id;
}b[maxl];
struct node
{
int l,r,mx;
}tr[maxl<<2];
inline void build(int k,int l,int r)
{
tr[k].l=l;tr[k].r=r;tr[k].mx=-inf;
if(l==r)
return;
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
inline bool cmp(const ind &a,const ind &b)
{
return a.val<b.val;
}
inline void prework()
{
//scanf("%d%d%d",&n,&L,&R);
rd(n);rd(L);rd(R);
tot=0;b[++tot]=ind{0,0};
for(int i=1;i<=n;i++)
{
//scanf("%d",&a[i]);
rd(a[i]);
sum[i]=sum[i-1]+a[i];
b[++tot]=ind{sum[i],i};
}
sort(b+1,b+1+tot,cmp);
for(int i=1;i<=tot;i++)
id[b[i].id]=i,c[i]=b[i].val;
build(1,1,tot);
}
inline void upd(int k,int l,int x)
{
if(tr[k].l==tr[k].r)
{
tr[k].mx=x;
return;
}
int mid=(tr[k].l+tr[k].r)>>1;
if(l<=mid)
upd(k<<1,l,x);
else
upd(k<<1|1,l,x);
tr[k].mx=max(tr[k<<1].mx,tr[k<<1|1].mx);
}
inline int qry(int k,int l,int r)
{
if(tr[k].l==l && tr[k].r==r)
return tr[k].mx;
int mid=(tr[k].l+tr[k].r)>>1;
if(r<=mid)
return qry(k<<1,l,r);
else if(l>mid)
return qry(k<<1|1,l,r);
else
return max(qry(k<<1,l,mid),qry(k<<1|1,mid+1,r));
}
inline void mainwork()
{
int hd=0,tl=-1,l,r;
dp[0]=0;
for(int i=1;i<=n;i++)
{
dp[i]=-inf+1;
if(hd<i-R)
upd(1,id[hd],-inf),hd++;
if(tl<i-L)
++tl,upd(1,id[tl],dp[tl]);
l=upper_bound(c+1,c+1+tot,sum[i])-c;
if(l<=tot)
dp[i]=max(dp[i],qry(1,l,tot)-1);
l=lower_bound(c+1,c+1+tot,sum[i])-c;
r=upper_bound(c+1,c+1+tot,sum[i])-c;
if(l<r)
dp[i]=max(dp[i],qry(1,l,r-1));
if(l>1)
dp[i]=max(dp[i],qry(1,1,l-1)+1);
}
}
inline void print()
{
printf("%d\n",dp[n]);
}
int main()
{
int t;
//scanf("%d",&t);
rd(t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}