zoukankan      html  css  js  c++  java
  • P2629 【好消息,坏消息】

    其实刚开始看到这道题,应该很多都会想到区间DP中的合并石子,开一个2倍的空间(严格来说的话应该是2n-1),将本来的环变成一个链式的结构。然后对于得到的消息,可以预处理一个前缀和,这样就可以很方便的知道 1~k-1 中是否会有 <0 的情况,那么这样就可以很容易得到第一种做法(这里的前缀和我写的有点麻烦,大佬们谅解一下)

    //暴力 
    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int a[2000005];
    int sum[2000005];
    bool check(int now){
    	for(int j=0;j<n;j++){
    		if(sum[now+j]-sum[now-1]<0) return false;
    	}
    	return true;
    }
    int main(){
    	scanf("%d",&n);
    	for(register int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		a[i+n]=a[i];
    		sum[i]=sum[i-1]+a[i];
    	}
    	int tot=1;
    	for(register int i=n+1;i<=2*n-1;i++){
    		sum[i]=sum[i-1]+a[tot];
    		tot++;
    	}
    	int ans=0;
    	for(register int i=1;i<=n;i++){
    		if(check(i)==true) ans++;
    	}
    	cout<<ans;
    	return 0;
    }
    

    看着感觉不能过,毕竟有点暴力的思想在里面,但是居然得了75分,我然后就想着快读+吸氧看能不能直接过,但事实上还是TLE了两个点,那么我们重新回到样例看一看

    当我们将这个环形链化,并且处理前缀和之后,我们可以得到以下的数据

    -3 5 1 2 -3 5 1
    -3 2 3 5  2 7 8
    

    那么对于每n个长度(即每一种不同的k的情况),我们可以得到分别的前缀和

    -3 5 1 2        //不同k的情况
    -3 2 3 5        //前缀和
    
    5 1 2 -3
    5 6 8  5
    
    1 2 -3 5
    1 3  0 5
    
    2 -3 5 1
    2 -1 4 5
    

    我们再进一步处理,得到每一组情况的最小前缀和分别为-3 5 0 -1,那么对于这其中大于等于0的情况的总数,就是最后答案的解了。所以这道题的思路,就是用单调队列维护区间的最小前缀和。至于单调队列,大家可以去搜搜滑动窗口,是单调队列的模板题

    //单调队列
    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int a[2000005];
    int sum[2000005];
    deque<int> q;
    int main() {
    	scanf("%d",&n);
    	for(register int i=1; i<=n; i++) {
    		scanf("%d",&a[i]);
    		a[i+n]=a[i];      //化环为链,因为方便写,这里实际是存储了2n个数据的 
    		sum[i]=sum[i-1]+a[i]; //处理前n个前缀和 
    	}
    	int tot=1;  //方便记录之后的前缀和 
    	for(register int i=n+1; i<=2*n-1; i++) {
    		sum[i]=sum[i-1]+a[tot];
    		tot++;     //处理n到2n-1个前缀和 
    	} //这里的前缀和处理可以其实直接写成一个for循环的,但是写的有些麻烦 
    	int ans=0;
    	for(register int i=1; i<=2*n-1; i++) {
    		while(!q.empty()&&sum[q.back()]>=sum[i]) q.pop_back(); //维护最小前缀和 
    		q.push_back(i);
    		if(i>=n) {    //一定是长度为n的 
    			while(!q.empty()&&q.front()<=i-n) q.pop_front();  //保证答案是在当前区间范围内 
    			if(sum[q.front()]-sum[i-n]>=0) ans++;    //最小前缀和 
    		}
    	}
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    云原生学习笔记(4)——Pod和容器设计模式
    云原生学习笔记(3)——Kubernetes基本概念
    云原生学习笔记(2)——容器基本概念
    云原生学习笔记(1)——云原生
    JAVA基础系列:JDK目录结构
    Mac 接手步骤
    JAVA基础系列:运行环境
    软件测试系列——Web界面检查点和测试原则
    软件测试系列——白盒测试
    软件测试系列——性能指标
  • 原文地址:https://www.cnblogs.com/Poetic-Rain/p/13088128.html
Copyright © 2011-2022 走看看