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;
    }
    
  • 相关阅读:
    ffmpeg rtmp推流 视频转码
    java日志发展史 log4j slf4j log4j2 jul jcl 日志和各种桥接包的关系
    nginx stream 流转发,可以转发rtmp、mysql访问流,转发rtmp、jdbc请求
    java web http 转https 通过nginx代理访问
    linux 服务器磁盘挂载
    novnc 通过websockify代理 配置多点访问
    linux 文件服务 minio 安装部署配置
    AOP实现原理,手写aop
    java 泛型
    JAVA反射getGenericSuperclass()用法
  • 原文地址:https://www.cnblogs.com/Poetic-Rain/p/13088128.html
Copyright © 2011-2022 走看看