• [TJOI2011]书架


    题意

    将序列(a_i)分成任意(k)部分,要求一部分的(a)值和不超过(m);最小化(每段权值的最大值之和)(,(nleq 100000))

    解法1

    显然动态规划,设(f_i)表示处理前(i)个数的最小值,(s)为前缀和,状态转移:(f_i=f_j+max(a_{j+1},a_{j+2}...a_i),(s_i-s_jleq m))

    考虑优化,首先,可转移的范围有单调性,可以用个指针(O(n))做,不再赘述

    维护线段树上的叶子:(ans=min(f+max(a)))(mx=max(a)),即(f_i=min(ans))

    每加入一个(a_i),考虑(i)前面连续比(a_i)小的一段([l,i-1]),这一段的(mx)更新为(a_i),(ans=a[l]+mx)

    ([l,i-1])可以用二分+查询,时间复杂度(O(nlog^2n))


    解法2

    上面的二分是没有必要的,求前面第一个比(a_i)大的数显然是单调栈预处理,优化至(O(nlogn))

    Code

    #include<bits/stdc++.h>
    #define N 400005
    #define Min(x,y) ((x)<(y)?(x):(y))
    #define Max(x,y) ((x)>(y)?(x):(y))
    using namespace std;
    typedef long long ll;
    int n,m,a[N],s[N];
    int f[N],pre[N];
    int mx[N<<2],ans[N<<2],sig[N<<2];
    int st[N],top;//一个单调栈预处理pre 
    
    template <class T>
    void read(T &x)
    {
    	char c; int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
    }
    
    void add_sign(int rt,int l,int r,int val)
    {
    	sig[rt]=val;
    	mx[rt]=val;
    	ans[rt]=f[l]+val;
    }
    void pushdown(int rt,int l,int r)
    {
    	if(!sig[rt]) return;
    	int mid=(l+r)>>1;
    	add_sign(rt<<1,l,mid,sig[rt]);
    	add_sign(rt<<1|1,mid+1,r,sig[rt]);
    	sig[rt]=0;
    }
    inline void pushup(int rt)
    {
    	ans[rt]=Min(ans[rt<<1],ans[rt<<1|1]);
    	mx[rt]=Max(mx[rt<<1],mx[rt<<1|1]);
    }
    void mmx(int rt,int l,int r,int x,int y,int val)//更新最大值 
    {
    	if(x>y) return;
    	pushdown(rt,l,r);
    	if(x<=l&&r<=y) return add_sign(rt,l,r,val);
    	int mid=(l+r)>>1;
    	if(x<=mid) mmx(rt<<1,l,mid,x,y,val);
    	if(y>mid) mmx(rt<<1|1,mid+1,r,x,y,val);
    	pushup(rt);
    }
    void modify(int rt,int l,int r,int x)
    {
    	if(l==r) { mx[rt]=a[l+1]; ans[rt]=f[l]+a[l+1]; return; }
    	int mid=(l+r)>>1;
    	pushdown(rt,l,r);
    	if(x<=mid) modify(rt<<1,l,mid,x);
    	else modify(rt<<1|1,mid+1,r,x);
    	pushup(rt);
    }
    int query(int rt,int l,int r,int x,int y)
    {
    	if(x<=l&&r<=y) return ans[rt];
    	int mid=(l+r)>>1;
    	pushdown(rt,l,r);
    	int ret=2000000000;
    	if(x<=mid) ret=min(ret,query(rt<<1,l,mid,x,y));
    	if(y>mid) ret=min(ret,query(rt<<1|1,mid+1,r,x,y));
    	return ret;
    }
    
    int main()
    {
    	read(n);read(m);
    	for(int i=1;i<=n;++i) read(a[i]),s[i]=s[i-1]+a[i];
    	for(int i=1;i<=n;++i)
    	{
    		while(top && a[st[top]]<=a[i]) --top;
    		pre[i]=st[top];//前面第一个比ai大的数 
    		st[++top]=i;
    	}
    	modify(1,0,n,0);
    	int l=0;//可转移范围 
    	for(int i=1;i<=n;++i)
    	{
    		while(s[i]-s[l]>m) ++l;
    		mmx(1,0,n,pre[i],i-1,a[i]);
    		f[i]=query(1,0,n,l,i-1);
    		modify(1,0,n,i);
    	}
    	cout<<f[n]<<endl;
    	return 0;
    }
    

    解法3

    花式运用题目单调性,用单调栈/队列:博客(O(n))

  • 相关阅读:
    maven/gradle 打包后自动上传到nexus仓库
    idea中怎么忽略(ignore)掉 .idea等文件
    MySQL优化一例
    微信调用照相拍照等 js 接口的权限配置 和 照片上传和下载实现
    {"errcode":40097,"errmsg":"invalid args hint: [vjNe7xxxxxx8vr19]"}——记录一次微信错误处理
    jsmooth compilation failed error null
    java.lang.UnsatisfiedLinkError: %1 不是有效的 Win32 应用程序。
    IE8 ajax缓存问题
    com.sun.xml.internal.ws.server.ServerRtException: Server Runtime Error: java.net.BindException: Cannot assign requested address: bind
    chrome 浏览器的预提取资源机制导致的一个请求发送两次的问题以及ClientAbortException异常
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11809005.html
Copyright © 2020-2023  润新知