2024/12/21课堂记录

目录

  1. 绿色通道
  2. 最大连续和

二分答案与单调队列的缝合怪

二分答案的基础上,把dp优化,用单调队列检验其合理性

代码很简单,真的就是把两个模板缝合在一起

#include<iostream>
using namespace std;
int dp[50005],a[50005],n,t;
int q[50005];
int head,tail; 
const int inf=0x3f3f3f3f;// 正无穷 
//  二分答案,最大值最小的问题 
//  dp[i]: 第i道题目必须写,往前最多可以空mid道题目 的最小花费时间 
//  朴素的dp 
int check(int mid)
{
	// 因为1-(mid+1)题前面都可以空着不写 
	//前面mid+1道题目,必须选一道 
    head=0,tail=1;
    for(int i=1;i<=n;i++)
    {
    	while(head<tail && q[head]<i-mid-1) head++;
    	dp[i]=dp[q[head]]+a[i];
    	while(head<tail &&  dp[q[tail-1]]>dp[i])tail--;
    	q[tail++]=i;
	}
    int ans=inf;
    for(int i=n-mid;i<=n;i++)
    {
    	ans=min(ans,dp[i]);
	}
	return ans<=t;
} 

int main()
{
	cin>>n>>t;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	//二分答案 
	int l=0,r=n;
	int ans=0x3f3f3f3f;
	while(l<=r)
	{
		int mid=(l+r)/2;
		if(check(mid)) // 二分最长空题的长度 
		{
			r=mid-1;
			ans=mid;
		}
		else
		{
			l=mid+1;
		}
	}
	cout<<ans<<endl;
	return 0; 
}

 


这个就更简单了,在单调队列模板的基础上,把原始数据变成前缀和,然后套模板,完事!

和扫描那题差不多,只不过吧最开始输入的数变成了前缀和,然后扫描直接维护输入进去的数,这个维护前缀和,然后这个要和全局变量进行比较,取最大值
 #include<iostream>
using namespace std;
int s[200005],a[200005],n,m;
int q[200005],dp[200005];
int head,tail; 
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		s[i]=s[i-1]+a[i];  //前缀和:s[i]=a[1]+a[2]+.....a[i] 
	}
	int ans=-0x3f3f3f3f; 
	head=0,tail=1;  //加入0编号 
	for(int i=1;i<=n;i++)
	{
		while(head<tail && q[head]<i-m)head++;
		
		ans=max(s[i]-s[q[head]],ans);
		
		while(head<tail && s[q[tail-1]]>s[i])tail--;
		q[tail++]=i;
	}
	/*
	int ans=-0x3f3f3f3f;
	for(int i=1;i<=n;i++)
	{
		int tmp=-0x3f3f3f3f;
		for(int j=i-1;j>=max(i-m,1);j--)
		{
			tmp=max(tmp,s[i]-s[j]); //a[j+1]+a[j+2]+...a[i] 
		}
		ans=max(tmp,ans);
	}
	*/

	cout<<ans<<endl;
	return 0; 
}

 

posted @ 2024-12-21 21:33  永韶  阅读(2)  评论(0编辑  收藏  举报