zoukankan      html  css  js  c++  java
  • CF1032G Chattering

    CF1032G Chattering

    题意

    思路

    对于每一个位置,它转移的范围是确定的。

    对于一段可以走到的区间,我们可以求出区间中所有点再能走到区间范围。

    于是这个就可以倍增进行转移。

    如何快速求出一段区间能走到的区间范围?也就是分别求出一段区间向左跳的位置的最小值和向右跳位置的最大值,发现这其实就是一个RMQ问题。但是因为还有倍增的时间复杂度,而且是没有修改的,那么我们可以利用ST表做到 查询。

    于是时间复杂度就变成了 的。

    这个转移的思想和ATcoder的一道题比较像。

    实现

    • 题目是一个环,所以我们需要将序列延长成三倍,然后在中间段查询。
    • 倍增时,若倍增到的左右端点距离已经超过 说明使完全覆盖,不优。
    • 最后需要将答案加一,因为第一次的时间并未算上。当 为 1 时,不需要传播,答案为 0。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    inline int read(){
    	int w=0,x=0;char c=getchar();
    	while(!isdigit(c))w|=c=='-',c=getchar();
    	while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    	return w?-x:x;
    }
    namespace star
    {
    	const int maxn=3e5+10;
    	int n,a[maxn];
    	int log[maxn];
    	int l[20][maxn],r[20][maxn];
    	struct RMQ{
    		int st[maxn][20],val[maxn];
    		int op;
    		inline int MAX(int x,int y){
    			return val[x]>val[y]?x:y;
    		}
    		inline void build(int *b,int n,int _op){
    			op=_op;
    			for(int i=1;i<=n;i++) st[i][0]=i,val[i]=op*b[i];
    			for(int j=1;j<=log[n];j++)
    				for(int i=1;i<=n;i++)
    					st[i][j]=MAX(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    		}
    		inline int query(int l,int r){
    			int k=log[r-l+1];
    			return MAX(st[l][k],st[r-(1<<k)+1][k]);
    		}
    	}L,R;
    	inline void work(){
    		n=read();
    		if(n==1)return (void)puts("0");
    		for(int i=2;i<=3*n;i++) log[i]=log[i>>1]+1;
    		for(int i=1;i<=n;i++) a[i]=a[i+n]=a[i+n+n]=read();
    		for(int i=0;i<=log[3*n];i++) l[i][1]=1,r[i][n*3]=3*n;
    		for(int i=1;i<=3*n;i++) l[0][i]=max(1,i-a[i]),r[0][i]=min(n*3,i+a[i]);
    		L.build(l[0],3*n,-1),R.build(r[0],3*n,1);
    		for(int l1,r1,j=1;j<=log[3*n];j++)
    			for(int i=1;i<=3*n;i++){
    				l1=L.query(l[j-1][i],r[j-1][i]);
    				r1=R.query(l[j-1][i],r[j-1][i]);
    				l[j][i]=min(l[j-1][l1],l[j-1][r1]);
    				r[j][i]=max(r[j-1][l1],r[j-1][r1]);
    			}
    		for(int i=n+1;i<=n<<1;i++){
    			int u=i,v=i,ans=0;
    			for(int j=log[n*3];~j;j--)
    				if(max(r[j][u],r[j][v])-min(l[j][u],l[j][v])+1<n){
    					int su=L.query(l[j][u],r[j][v]),sv=R.query(l[j][u],r[j][v]);
    					u=su,v=sv;
    					ans+=(1<<j);
    				}
    			printf("%d ",ans+1);
    		}
    	}
    }
    signed main(){
    	star::work();
    	return 0;
    }
    
  • 相关阅读:
    上周热点回顾(12.1312.19)
    上周热点回顾(12.612.12)
    上周热点回顾(11.1511.21)
    上周热点回顾(11.2211.28)
    上周热点回顾(11.2912.5)
    [转]ITIL知识体系简介
    [书目20211113]Python自动化测试入门与进阶实战
    [转]敏捷宣言的内容及准则
    [书目20211212]IT运维之道
    python做量化交易干货分享
  • 原文地址:https://www.cnblogs.com/BrotherHood/p/13904569.html
Copyright © 2011-2022 走看看