zoukankan      html  css  js  c++  java
  • 【单调队列】

    单调队列优化

    做动态规划时常常会见到形如这样的转移方程:(f[i] = optimize{g(j)|L[i] ≤ j < i brace+w[i])
    其中(L[1] ≤ L[2] ≤ · · · ≤ L[n]) ((g[j])表示一个和j或(f[j])有关的函数,(w[i])表示一个和i有关的函数)

    有这样一个性质:如果存在两个数 (j,k),使得 (k ≤ j),而且(g(k) ≤ g(j) (opt = max))(g(j) ≤ g(k)(opt = min)),则决策k 是毫无用处的。

    根据 (L[i]) 单调的特性,如果 k 可以作为合法决策,那么 j一定可以作为合法决策,又因为 j 比 k 要优 (注意: 在这个经典模型中,“优”是绝对的,与当前正在计算的状态⽆关),因此如果把表中的决策按照 j 排序的话,则 (g(j)) 必然不升((opt=max)) 或必然不降 ((opt=min))

    1、 计算(g(x)),并将其插入到单调队列的尾部,同时维持队列的单调性(不断地出队,直到队列单调为止)。

    2、 队首元素出队,直到队首元素在给定的范围中。

    3、 此时,队首元素就是状态f(x)的最优决策,

    重复上述步骤直到所有的函数值均被计算出来。不难看出这样的算法均摊时间复杂度是(O(1))的 因此使用单调队列即可将原本 (O(N^2)) 的复杂度降至(O(N))

    实战

    滑动窗口

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1000000+5,M=2e5+5,inf=0x3f3f3f3f,P=19650827;
    int n,m,a[N],q1[N],q2[N],ans1[N],ans2[N];
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    int main(){
        rd(n),rd(m);
        for(int i=1;i<=n;++i) rd(a[i]);
        int l1,r1=0,l2=l1=1,r2=0;
        for(int i=1;i<=n;++i){
            while(l1<=r1&&a[i]<a[q1[r1]]) --r1;
            while(l2<=r2&&a[i]>a[q2[r2]]) --r2;
            while(l1<=r1&&q1[l1]<=i-m) ++l1;
            while(l2<=r2&&q2[l2]<=i-m) ++l2;
            q1[++r1]=i,q2[++r2]=i;
    		if(l1<=r1) ans1[i]=a[q1[l1]];
    		if(l2<=r2) ans2[i]=a[q2[l2]];
    	}
        for(int i=m;i<=n;++i) printf("%d ",ans1[i]);
        puts("");
        for(int i=m;i<=n;++i) printf("%d ",ans2[i]);
    	return 0;
    }
    

    P3957跳房子

    二分+单调队列

    g越大 灵活性越高 ....所以二分
    在g不变的情况下 随着向右跳 l和r也在递增 所以用单调队列

    (有问题)

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define Max(x,y) ((x)>(y)?(x):(y))
    const int N=500000+5,M=2e5+5,inf=0x3f3f3f3f,P=19650827;
    int n,d,k,a[N],s[N];
    ll sum=0,f[N];
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    int q[N];
    bool check(int mid){
    	for(int i=1;i<=n;++i) f[i]=-inf;
    	memset(q,0,sizeof(q));
    	int h=1,t=0,ma=Max(1,d-mid),mb=d+mid;
    	for(int i=1,j=0;i<=n;++i){
    		for(;j<i&&s[i]-s[j]>=ma;++j)
    		if(f[j]!=-inf){//j可到达
    			while(h<=t&&f[j]>f[q[t]]) --t;
    			q[++t]=j;
    		}
    		while(h<=t&&s[i]-s[q[h]]>mb) ++h;//除去不合法状态
    		if(h<=t) f[i]=a[i]+f[q[h]];
    	}
    	for(int i=1;i<=n;++i) if(f[i]>=k) return 1;
    	return 0;
    }
    
    int main(){
    	freopen("in2.txt","r",stdin);
    	//freopen("xor.out","w",stdout);
    	rd(n),rd(d),rd(k);
    	int l=0,r=d,mid;
    	for(int i=1;i<=n;++i) rd(s[i]),rd(a[i]),sum+=Max(0,a[i]),r=Max(r,s[i]);
    	if(sum<k) return puts("-1"),0;
    	while(l<r){
    		mid=l+r>>1;
    		if(check(mid)) r=mid;
    		else l=mid+1;
    	}
    	printf("%d",r);
    	return 0;
    }
    
  • 相关阅读:
    『Delphi』字符串操作——返回子串出现的位置
    2007:远见、劲取、专注
    『转载』个人博客吸引风投关注成可盈利业务
    [和管子对话] 1 200745/对面向对象的你言我语
    『Delphi』File not found的解决办法
    Ruby学习1字符串
    聚集表(clustered table)data page中的数据行可以无序
    通过DBCC PAGE查看页信息验证聚集索引和非聚集索引节点信息
    查看SQL Server Resource Database以及修改系统表
    SQL Server的还原(2)——STOPAT
  • 原文地址:https://www.cnblogs.com/lxyyyy/p/11391444.html
Copyright © 2011-2022 走看看