• 【ybtoj】【单调队列】出题方案


    题意

    现在小泽的手上有 n 道难题,编号分别为 1∼n ,第 i 道题的难度系数是 ai 。
    小泽想用这些题出比赛,他会把题目按照编号划分为若干个非空连续区间,每个区间对应了一场比赛。
    特别的,如果某场比赛的题目难度系数之和超过了给定的常数 m ,这场比赛会过于毒瘤,所以他不希望出现这样的情况。
    定义每场比赛的难度系数为这场比赛所有题目难度系数的最大值。
    小泽想让你找出一组合法方案,使得所有比赛的难度系数之和最小。
    (n)(3×10^5)(1)(a_i)(10^6)(1)(m)(1.1×10^9)

    题解

    个人觉得思维难度非常大的一道题,卡了我很久。
    考虑朴素 DP: (dp_i=min{dp_j}+max a_k).
    然而这里后面的 (max a_k)不独立,而是还与前面的 (j) 有关,所以不能简单地用单调队列优化。
    先假设对 (a_k) 做单调队列维护最大值,很好维护何时出队,入队,但是此时仍然不知道 (j) 取何值时为 (dp_i) 的转移点。
    考虑对单调队列中任何一个 (q_j),由于单调队列内部单调递减,那么紧接着 (q_j) 的下一个元素 (q_{j+1}) 的位置一定是 (j) 点对于此时的最大 (a_k),即此时 (max a_k=q_{j+1}).
    那么对于单调队列每相邻两个元素维护 (dp_j+a_{j+1}),每次取最小值即可。
    同时维护的过程中还要随着单调队列移动,动态删除点,查询最小值,可以用 STL 中的 multiset。
    注意:当单调队列长度 (ge2) 时才对队列进行相关操作。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int INF = 0x3f3f3f3f,N = 3e5+10;
    inline ll read()
    {
    	ll ret=0;char ch=' ',c=getchar();
    	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
    	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
    	return ch=='-'?-ret:ret;
    }
    
    int n,m;
    ll a[N],sum[N],dp[N];
    inline ll Sum(int l,int r){ return l>r?-1e18:sum[r]-sum[l-1];}
    multiset<ll>s;
    ll q[N];
    int main()
    {
    	memset(dp,0x3f,sizeof(dp));
    	n=read(),m=read();
    	for(int i=1;i<=n;i++) a[i]=read(),sum[i]=sum[i-1]+a[i];
    	int l=1,r=0;
    	int j=0;
    	dp[0]=0;//初始化 
    	for(int i=0;i<=n;i++) //注意把i=0的情况放入队列 
    	{
    		while(Sum(j+1,i)>m) j++;
    		while(l<=r&&q[l]<j) 
    		{
    			if(r-l+1>=2) s.erase(s.find(dp[q[l]]+a[q[l+1]]));
    			l++; 
    		}
    		while(l<=r&&a[q[r]]<=a[i]) 
    		{	
    			if(r-l+1>=2) s.erase(s.find(dp[q[r-1]]+a[q[r]]));
    			r--;
    		}
    		if(l<=r) s.insert(dp[q[r]]+a[i]);
    		q[++r]=i;
    		dp[i]=dp[j]+a[q[l]];
    		if(r-l+1>=2) dp[i]=min(dp[i],*s.begin());
    	}
    	printf("%lld",dp[n]);
    	return 0;
    }
    
    

    参考博客

    Last-Order

  • 相关阅读:
    MFC Document/View 3
    MFC Document/View 2
    c++基本类型&&&c++string与c风格字符串的相互转化
    C++不同变量所在内存&&new malloc的区别
    C# 操作Excel 复选框
    prepareStatement与Statement的区别
    Oracle查询用户所有表、字段等信息
    同样的用户和密码,PL/SQL可以正常登录,C#程序却出现 ORA-1017 用户名/口令无效
    javascript原生态的同步异步请求实现
    SQL 数据库是否安全
  • 原文地址:https://www.cnblogs.com/conprour/p/15303043.html
Copyright © 2020-2023  润新知