zoukankan      html  css  js  c++  java
  • 「CF689D Friends and Subsequences」

    题目大意

    给出两个长度为 (n) 的序列 (a)(b),计算有多少对 (l,r) 满足 (max{a_l,a_{l+1},dots,a_{r-1},a_r}=min{b_l,b_{l+1},dots,b_{r-1},b_r}).

    分析

    考虑 (max)((min))的一些性质,(max{a_l,a_{l+1},dots,a_{r-1},a_r}leqmax{a_l,a_{l+1},dots,a_r,a_{r+1}})((min{b_l,b_{l+1},dots,b_{r-1},b_r}geqmin{b_l,b_{l+1},dots,b_r,b_{r+1}})),那么就可以发现这个东西是单调的,所以就很容易想到去二分查找.枚举左端点,查找右端点,可以发现符合条件的右端点肯定是一段区间(可能没有),那么可以二分出这个合法区间的左端点和右端点,然后就可以直接计算贡献了,考虑到取药计算区间最值,所以可以用st表维护.

    代码

    #include<bits/stdc++.h>
    #define REP(i,first,last) for(int i=first;i<=last;++i)
    #define DOW(i,first,last) for(int i=first;i>=last;--i)
    using namespace std;
    const int MAXN=3e5+7;
    int n;
    int a[MAXN];
    int log_2[MAXN];
    int lrmax[MAXN][24];
    int lrmin[MAXN][24];
    int QueryMax(int left,int right)//查询区间最大值
    {
    	int len=log_2[right-left+1];
    	return max(lrmax[left][len],lrmax[right-(1<<len)+1][len]);
    }
    int QueryMin(int left,int right)//查询区间最小值
    {
    	int len=log_2[right-left+1];
    	return min(lrmin[left][len],lrmin[right-(1<<len)+1][len]);
    }
    int main()
    {
    	scanf("%d",&n);
    	REP(i,1,n)
    	{
    		scanf("%d",&lrmax[i][0]);
    	}
    	REP(i,1,n)
    	{
    		scanf("%d",&lrmin[i][0]);
    	}
    	int now=0;
    	REP(i,1,n)//预处理log2(向下取整)
    	{
    		if(i==(1<<(now+1)))
    		{
    			++now;
    		}
    		log_2[i]=now;
    	}
    	REP(i,1,now)//预处理st表
    	{
    		REP(j,1,n+1-(1<<i))
    		{
    			lrmax[j][i]=max(lrmax[j][i-1],lrmax[j+(1<<(i-1))][i-1]);
    			lrmin[j][i]=min(lrmin[j][i-1],lrmin[j+(1<<(i-1))][i-1]);
    		}
    	}
    	int left,right,middle,l_appear,r_appear;
    	long long answer=0;//注意开long long
    	REP(i,1,n)
    	{
    		left=i;
    		right=n;
    		l_appear=0;
    		r_appear=0;
    		while(left<=right)//二分右端点
    		{
    			middle=(left+right)>>1;
    			if(QueryMax(i,middle)>QueryMin(i,middle))//如果max大了那么就减小
    			{
    				right=middle-1;
    			}
    			else
    			{
    				if(QueryMax(i,middle)==QueryMin(i,middle))//如果max和min相等则记录位置
    				{
    					r_appear=middle;
    				}
    				left=middle+1;
    			}
    		}
    		left=i;
    		right=n;
    		while(left<=right)//同理二分出左端点
    		{
    			middle=(left+right)>>1;
    			if(QueryMax(i,middle)>=QueryMin(i,middle))
    			{
    				if(QueryMax(i,middle)==QueryMin(i,middle))
    				{
    					l_appear=middle;
    				}
    				right=middle-1;
    			}
    			else
    			{
    				left=middle+1;
    			}
    		}
    		if(l_appear&&r_appear)//如果存在则计算贡献
    		{
    			answer+=(r_appear-l_appear+1);
    		}
    	}
    	printf("%lld",answer);
    	return 0;
    }
    
  • 相关阅读:
    Unity3D学习笔记(十九):UGUI、Image、Text、Button
    Unity3D学习笔记(十八):动画内容补充
    Unity3D学习笔记(十七):IK动画、粒子系统和塔防
    Unity3D学习笔记(十六):Animator新动画
    Unity3D学习笔记(十五):寻路系统
    Unity3D学习笔记(十四):Animation旧动画
    Unity3D学习笔记(十三):委托、考试复习
    Unity3D学习笔记(十二):2D模式和异步资源加载
    加密解密
    linux 常用命令
  • 原文地址:https://www.cnblogs.com/Sxy_Limit/p/12671605.html
Copyright © 2011-2022 走看看