zoukankan      html  css  js  c++  java
  • 题解「Japan Alumni Group Summer Camp 2018 Day 2J AB Sort」

    GMOJ100137 胖头鱼的排序

    题意

    对字符串 (s) 进行一次操作,使得 (s) 中所有为 ( ext{BA}) 的子串同时变为 ( ext{AB}) 。定义 (mathrm{f}(s)) 表示不断对 (s) 进行上述操作,直到无法再操作为止,最多能对 (s) 进行的操作次数。

    给定字符串 (s) ,要求支持区间 ( ext{AB}) 翻转,查询 (mathrm{f}('mathrm{B}'+s+'mathrm{A}'))

    题解

    发现进行这样的操作的本质是对 (s) 排序,最后所有的 ( ext{A}) 都在 ( ext{B}) 的前面。也就是说,只要存在一个 ( ext{B})( ext{A}) 前面,那么这个字符串就还能被操作。发现所有 ( ext{B}) 的相对位置是不变的,所以只需要考虑最左边的那个 ( ext{B}) 被移动到正确的位置上的操作次数。

    显然,如果每次操作都让最左边的 ( ext{B}) 移动了一位,那么总操作次数即为 (mathrm{cnt}( ext{A})+1) (这里 (mathrm{cnt}) 计算的是 (s) 中字母的个数,不包括两段加入的字符),但是并不是每次操作都会移动最左边的 ( ext{B}) 。不难发现,本次操作不会移动某个位置的 ( ext{B}) ,当且仅当它后面紧跟着一个 ( ext{B}) ,而不是 ( ext{A})(后面没有字符除外),我们将这种情况称作这个 ( ext{B}) 被后面的 ( ext{B}) 阻挡。

    考虑下面这种情况(假设最后一段 ( ext{A}) 足够长):

    [ ext{B}~overbrace{ ext{AA}ldots ext{AA}}^{c_1}~overbrace{ ext{BB}ldots ext{BB}}^{c_2}~ ext{AA}ldots ]

    (c_1geq c_2) ,那么当最左边的 ( ext{B}) 移动到第一段 ( ext{A}) 之后时,长度为 (c_2) 的那段 ( ext{B}) 已经全部移动,即此时最左边的 ( ext{B}) 后面紧接着的是一个 ( ext{A}) ,那么它就可以继续向后移动,换而言之,这段长度为 (c_2)( ext{B}) 对最左边的 ( ext{B}) 的移动无影响。

    否则 (c_1<c_2) ,最左边的 (B) 移动到 ( ext{A}) 之后时,后面那段 ( ext{B}) 还有 (c_2-c_1) 个没有移动,即它后面紧接着有 (c_2-c_1)( ext{B}) ,再进行操作时这个 ( ext{B}) 就无法移动了,它再次移动还需要 (c_2-c_1) 次操作。

    如果最后一段 ( ext{A}) 不够长,即下面一种情况:

    [ ext{B}~overbrace{ ext{AA}ldots ext{AA}}^{c_1}~overbrace{ ext{BB}ldots ext{BB}}^{c_2}~overbrace{ ext{AA}ldots ext{AA}}^{c_3}~overbrace{ ext{BB}ldots ext{BB}}^{c_4}~ ext{AA}ldots ]

    其中 (c_3<c_4) ,那么 (c_2) 这一段就不能顺利地走过 (c_3) 这一段了,它会被后面 (c_4) 这一段阻挡 (c_4-c_3) 次操作,那么最左边的 ( ext{B}) 就会被阻挡 (c_4+c_2-c_1-c_3) 次操作。

    到这里就能大概看出结论了:若将 ( ext{A}) 看成 (-1)( ext{B}) 看成 (1) ,序列的最大前缀和为 (mathrm{lmax}(s)) ,答案即为 (mathrm{cnt}( ext{A})+1+mathrm{lmax}(s))

    用线段树维护即可。

    Code:

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <climits>
    #define Rint register int
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long lxl;
    const int maxn=2e5+5;
    
    template <typename T>
    inline void read(T &x)
    {
    	x=0;T f=1;char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	x*=f;
    }
    
    int n,q;
    char s[maxn];
    
    namespace Segment_Tree
    {
    	struct node
    	{
    		int l,r,cntA,cntB;
    		int sum,lmin,lmax;
    		bool tag;
    		node(int l,int r,int cntA,int cntB,int sum,int lmin=0,int lmax=0,bool tag=false)
    			:l(l),r(r),cntA(cntA),cntB(cntB),sum(sum),lmin(lmin),lmax(lmax),tag(tag){}
    		node(){}
    		inline node operator + (const node &T)const
    		{
    			node res(l,T.r,cntA+T.cntA,cntB+T.cntB,sum+T.sum);
    			res.lmin=min(lmin,sum+T.lmin);
    			res.lmax=max(lmax,sum+T.lmax);
    			return res;
    		}
    	}tree[maxn<<2];
    	#define ls (p<<1)
    	#define rs (p<<1|1)
    	inline void reverse(int p)
    	{
    		if(!p) return;
    		swap(tree[p].cntA,tree[p].cntB);
    		swap(tree[p].lmin,tree[p].lmax);
    		tree[p].lmin=-tree[p].lmin;
    		tree[p].lmax=-tree[p].lmax;
    		tree[p].sum=-tree[p].sum;
    		tree[p].tag^=1;
    	}
    	inline void push_down(int p)
    	{
    		if(!tree[p].tag) return;
    		reverse(ls);
    		reverse(rs);
    		tree[p].tag=0;
    	}
    	inline void set(int p,char c)
    	{
    		tree[p].sum=c=='A'?-1:1;
    		c=='A'?(tree[p].cntA=1):(tree[p].cntB=1);
    		tree[p].lmin=min(0,tree[p].sum);
    		tree[p].lmax=max(0,tree[p].sum);
    	}
    	void build(int p,int l,int r)
    	{
    		tree[p]=node(l,r,0,0,0);
    		if(l==r) return set(p,s[l]),void();
    		int mid=(l+r)>>1;
    		build(ls,l,mid);
    		build(rs,mid+1,r);
    		tree[p]=tree[ls]+tree[rs];
    	}
    	void modify(int p,int L,int R)
    	{
    		int l=tree[p].l,r=tree[p].r;
    		if(L<=l&&r<=R) return reverse(p),void();
    		push_down(p);
    		int mid=(l+r)>>1;
    		if(L<=mid) modify(ls,L,R);
    		if(R>mid) modify(rs,L,R);
    		tree[p]=tree[ls]+tree[rs];
    	}
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("P100137.in","r",stdin);
    #endif
    	read(n);
    	scanf(" %s
    ",s+1);
    	Segment_Tree::build(1,1,n);
    	read(q);
    	int l,r;
    	while(q--)
    	{
    		read(l),read(r);++l,++r;
    		Segment_Tree::modify(1,l,r);
    		printf("%d
    ",Segment_Tree::tree[1].cntA+Segment_Tree::tree[1].lmax+1);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    png格式的img元素直接设置背景色、border-radius等属性,不需再包裹div造成冗余
    :before伪元素的灵活用法——前置元素的装饰
    linear-gradient在实战项目中的灵活运用——position和size的深入理解
    算法之单向链表
    awk(二)
    awk(一)
    grep与正则表达式
    编程原理
    Shell-bash的基本特性
    DNS域名轮循业务监控
  • 原文地址:https://www.cnblogs.com/syc233/p/13973224.html
Copyright © 2011-2022 走看看