1002 Breaking Down News 2020杭电多校第8场

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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值