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;
    }
    
  • 相关阅读:
    POJ 1201 Intervals 差分约束
    netframework2.0,asp.net2.0,vs.net 2005
    学习.net第一天
    VS.NET 2003 控件命名规范
    .Net生成共享程序集
    汉字的编码
    [转]用C#实现连接池
    SQL表自连接用法
    一道很好玩的OOP面试题,今天比较有空,所有做了一下
    C#编程规范(2008年4月新版)
  • 原文地址:https://www.cnblogs.com/Sxy_Limit/p/12671605.html
Copyright © 2011-2022 走看看