zoukankan      html  css  js  c++  java
  • P5858 「SWTR-03」Golden Sword

    题面:

    Link

    题面有点长,不想粘了,QAQ。

    题解:

    一句话题意,你有 (n) 件物品需要依次放进去,每个物品放进去之后会得到一定的权值,为当前锅炉里面的物品的数量乘以 (a_i)

    每次在放这件物品之前,你可以那出 (0-s) 件物品出来,但锅炉里物品的数量不能超过 (w)

    (dp) 状态应该很好想。

    设$ f[i][j]$ 表示放 第 (i) 件有 (j) 个物品在锅炉里的最大价值。

    那么就可以有前一天的状态转移过来。

    则有 (f[i][j] = max(f[i-1][k] + j * a[i]))

    以及不拿出来的情况 (f[i][j] = max(f[i-1][j-1]))

    然后你就可以拿到 (85) 分的好成绩,大雾

    我们考虑一下优化,发现后面的那段柿子是个很经典的求一段区间的最小值的形式。

    那我们就可以采用一下单调队列优化一下。

    注意枚举 (k) 的时候要倒着枚举,因为你 用到的是 (j) 之后得状态,要先把他 (f[i-1]) 后面的状态先入队。

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define int long long
    int n,w,s,head,tail,a[5560],f[5560][5560],q[5560];
    inline int read()
    {
    	int s = 0,w = 1; char ch = getchar();
    	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9'){s =s * 10+ch - '0'; ch = getchar();}
    	return s * w;
    }
    signed main()
    {
    	n = read(); w = read(); s = read(); int ans = -1e13;
    	for(int i = 1; i <= n; i++) a[i] = read();
    	memset(f,128,sizeof(f));
    	f[1][1] = a[1];
    	for(int i = 2; i <= n; i++)
    	{
    		head = 1, tail = 0;
    		for(int j = w; j >= 1; j--)
    		{
    			f[i][j] = max(f[i][j],f[i-1][j-1] + j * a[i]);//不放的情况
    			while(head <= tail && q[head] > min(w,j+s-1)) head++;//单调队列优化一下
    			while(head <= tail && f[i-1][q[tail]] <= f[i-1][j]) tail--;
    			q[++tail] = j;
    			f[i][j] = max(f[i][j],f[i-1][q[head]] + j * a[i]);
    		}
    	}
    	for(int i = 1; i <= w; i++) ans = max(ans,f[n][i]);
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    测试代码运行效率
    用宏实现的单例模式
    上传控件的按钮改为图片
    ODAC的使用笔记
    ASP.NET防止重复提交
    向SharePoint图片库添加Item
    获取页面上用户控件的子控件ID
    SharePoint的WebService的应用
    GridView中HyperLinkField的链接使用JavaScript问题
    C#日期验证的正则表达式
  • 原文地址:https://www.cnblogs.com/genshy/p/13694449.html
Copyright © 2011-2022 走看看