• [DarkBZOJ3636] 教义问答手册


    前言

    如何评价题解看不懂只能自己把这道题想出来。

    明明就是懒得看题解啊喂!(#`O′)

    个人感觉这个应该不算 ( t cdq)分治,但是又不知道怎么分类,于是。。。

    题目

    DARKBZOJ

    讲解

    分治其实就是按一定顺序做就可以保证时间复杂度的暴力。

    所以我们先考虑 (O(n^2))( t dp),显然我们可以令 (dp_{l,r}) 表示区间 ([l,r]) 的最大划分。

    考虑优化。

    我们注意到 (Lle 50),这给了我们乱搞的资本。

    考虑将询问丢到各个区间里面分治,如果一个询问完全被一个大区间 ([l,r]) 的子区间包含,给这个子区间就好。这里我们认为 ([l,r]) 的子区间为 ([l,mid])([mid+1,r]) ,和线段树是一样的。

    如果这个询问跨越了中间的边界 (mid) 怎么办?由于 (L) 很小,我们可以枚举它在左边的长度,当然在右边的长度也可以计算出来。中间越界的部分是一个长度为 (L) 的区间加,两边是可以预处理的一个 ( t dp)

    思路不难,细节有点多。

    代码

    //12252024832524
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define TT template<typename T>
    using namespace std; 
    
    typedef long long LL;
    const int MAXN = 100005;
    const int MAXL = 52;
    int n,len,Q;
    int a[MAXN],ans[MAXN];
    
    LL Read()
    {
    	LL x = 0,f = 1;char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    struct Query
    {
    	int l,r,ID;
    }q[MAXN],lq[MAXN],rq[MAXN];
    
    int dpl[MAXL][MAXN],dpr[MAXL][MAXN];//这里的l,r指的是左边的区间和右边的区间 
    //右边界空出i,j开始dp [j,mid-i];左边界空出i,j开始dp [mid+1+i,j]
    void workl(int l,int r)
    {
    	for(int i = 0;i < len && r-i >= l;++ i)//细品这里取等的原因 
    	{
    		int R = r-i;
    		for(int j = R+1;j >= l;-- j)
    		{
    			if(R-j+1 < len) dpl[i][j] = 0;
    			else dpl[i][j] = Max(dpl[i][j+1],dpl[i][j+len] + a[j+len-1]);
    		}
    	}
    } 
    void workr(int l,int r)
    {
    	for(int i = 0;i < len && l+i <= r;++ i)
    	{
    		int L = l+i;
    		for(int j = L-1;j <= r;++ j)
    		{
    			if(j-L+1 < len) dpr[i][j] = 0;
    			else dpr[i][j] = Max(dpr[i][j-1],dpr[i][j-len] + a[j]);
    		}
    	}
    }
    
    void solve(int l,int r,int ql,int qr)
    {
    	if(ql > qr || r-l+1 < len) return;
    	if(l == r)
    	{
    		for(int i = ql;i <= qr;++ i) ans[q[i].ID] = Max(a[l],0);
    		return;
    	}
    	int mid = (l+r) >> 1,ln = 0,rn = 0;
    	workl(l,mid); workr(mid+1,r);
    	for(int i = ql;i <= qr;++ i)
    	{
    		if(q[i].r <= mid) lq[++ln] = q[i];
    		else if(q[i].l > mid) rq[++rn] = q[i];
    		else
    		{
    			ans[q[i].ID] = Max(0,dpl[0][q[i].l]+dpr[0][q[i].r]);
    			int LL = Max(0,mid+len-q[i].r),RR = Min(len,mid-q[i].l+1);
    			for(int j = LL;j <= RR;++ j)//枚举左边剩多少 
    				ans[q[i].ID] = Max(ans[q[i].ID],dpl[j][q[i].l] + dpr[len-j][q[i].r] + a[mid+len-j]);
    		}
    	}
    	for(int i = 1;i <= ln;++ i) q[ql+i-1] = lq[i];
    	for(int i = 1;i <= rn;++ i) q[ql+ln+i-1] = rq[i];
    	solve(l,mid,ql,ql+ln-1); solve(mid+1,r,ql+ln,ql+ln+rn-1);
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	n = Read(); len = Read();
    	for(int i = 1;i <= n;++ i) a[i] = Read() + a[i-1];
    	for(int i = n;i > len;-- i) a[i] -= a[i-len];
    	Q = Read();
    	for(int i = 1;i <= Q;++ i)
    	{
    		q[i].l = Read();
    		q[i].r = Read();
    		q[i].ID = i;
    	}
    	solve(1,n,1,Q);
    	for(int i = 1;i <= Q;++ i) Put(ans[i],'
    ');
    	return 0;
    }
    
  • 相关阅读:
    AS3.0纯代码编写的两款loading效果
    AS3.0 Vector的运用
    java 垃圾回收总结(1)
    as3垃圾回收机制
    AS3.0 效率优化
    数组去重的方法
    javascript 的垃圾回收机制讲一下
    浅拷贝和深拷贝
    判断 js 类型的方式
    前端安全问题?
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/14491586.html
Copyright © 2020-2023  润新知