zoukankan      html  css  js  c++  java
  • luogu P4852 yyf hates choukapai 单调队列优化dp

    LINK:yyf hates choukapai

    由于赶时间 要做的题有点小多。。 所以简略概述一下。

    容易想到一个暴力dp (f_{i,j,k})表示到了第i张牌此时连抽j次已经单抽k次的最大值.

    转移可以刷表转移 复杂度O(1) 期望得分50.

    考虑(d==m)时可以发现第三维可以直接去掉了 然后这样dp是(scdot n)的 加上 上面的做法 期望得分70.

    考虑正解 状态都已经爆了 所以需要降维 考虑将第三维给扔掉。

    那么如何满足限制?容易发现最优解中一定是一段单抽一段连抽(这不是废话么

    考虑0的位置之前想象成连抽 最后再加c张牌全部为0 强制连抽。

    这样就可以在每次连抽的位置进行dp 然后连抽和连抽之间选择单抽 然后强制单抽满足条件即可。

    即设状态(f_{i,j})表示到了第i个位置单抽了j次且第i个位置是第j次连抽的结尾。

    之所以后面加上c张牌是为了避免比较繁琐的分类讨论。可以发现可以进行单调队列优化。

    输出方案随便记录一下即可。

    code
    //#include<bitsstdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 1000000000000000ll
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define gc(a) scanf("%s",a+1)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define vep(p,n,i) for(RE int i=p;i<n;++i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define P 1000000007
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-8
    #define sq sqrt
    #define S second
    #define F first
    #define mod 998244353
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        RE int x=0,f=1;RE char ch=getc();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
        return x*f;
    }
    const int MAXN=210010;
    int n,m,s,d,c;
    int f[MAXN][44],g[MAXN][44];
    int a[MAXN],q[MAXN],l,r,v[MAXN];
    inline void get_path(int x,int y)
    {
    	if(!y)return;
    	v[x-c+1]=1;get_path(g[x][y],y-1);
    }
    int main()
    {
    	//freopen("1.in","r",stdin);
    	get(n)+1;get(m);get(c);get(d);
    	s=n*c+m-c;
    	rep(1,s,i)get(a[i]);
    	s+=c;rep(1,s,i)a[i]+=a[i-1];
    	memset(f,0xcf,sizeof(f));
    	f[0][0]=0;
    	rep(1,n,j)
    	{
    		l=1;r=0;
    		if(1-c>=0&&f[0][j-1]>=0)q[++r]=1-c;
    		rep(1,s,i)
    		{
    			while(l<=r&&q[l]<i-c-d)++l;
    			if(l<=r)
    			{
    				f[i][j]=a[i-c+1]-a[q[l]]+f[q[l]][j-1];
    				g[i][j]=q[l];
    			}
    			if(i+1-c>=0&&f[i+1-c][j-1]>=0)
    			{
    				while(l<=r&&f[q[r]][j-1]-a[q[r]]<=f[i+1-c][j-1]-a[i+1-c])--r;
    				q[++r]=i+1-c;
    			}
    		}
    	}
    	put(f[s][n]);
    	get_path(s,n);
    	rep(1,s-c,i)if(v[i])printf("%d ",i);
    	return 0;
    }
    
  • 相关阅读:
    全文本的检索
    网卡配置
    linux解压命令
    Session
    swoole安装
    Linux 系统磁盘满处理方法
    php写入和读取文件内容
    PHP读取文件夹的文件列表
    php 公历农历互相转换
    PHP实现RESTful风格的API实例
  • 原文地址:https://www.cnblogs.com/chdy/p/13284246.html
Copyright © 2011-2022 走看看