zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:寿司(暴力)

    题目描述

    小$c$是一名$oier$。最近,他发现他的数据结构好像学傻了。因为他在刷题时碰到了一道傻逼数据结构题,强行使用了平衡树来解决,卡着时间$AC$。为此,他被狠狠地嘲讽了一番。于是,小$c$找了大量的数据结构题来做。

    昨天,小$c$正在吃寿司,突然发现许多盘寿司围成了一个圆圈,这些寿司中有红色的也有蓝色的。由于小$c$看交错的颜色非常不爽,想通过一些操作,使得所有的红色寿司形成了一块连续的区域,蓝色的寿司也形成了一块连续的区域。如果小$c$每次只可以交换相邻的两盘寿司,那么最少需要多少步才可以达到小$c$的要求呢?由于他做题做多了,脑袋已经有点不清醒了,于是这个问题就交给你了。


    输入格式

    第一行一个数$T$,表示数据组数。
    接下来$T$行,每行一行由$B$和$R$组成的字符串,$B$表示蓝色,$R$表示红色。第$i$个字符描述顺时针数第$i$盘寿司的颜色。注意,最后一盘寿司和第$1$盘寿司是相邻的。


    输出格式

    对于每组数据,输出一行表示最小的交换次数。


    样例

    样例输入

    1
    BBRBBRBBBRRR

    样例输出

    5


    数据范围与提示

    样例说明:

    以下说明交换的步骤:
    交换位置$2$、位置$3$上的寿司;
    交换位置$1$、位置$2$上的寿司;
    交换位置$6$、位置$7$上的寿司;
    交换位置$7$、位置$8$上的寿司;
    交换位置$8$、位置$9$上的寿司;

    数据范围:

    $Tleqslant 10$

    $nleqslant 1,000,000$


    题解

    算法一:

    爆搜,枚举所有走法。可以获得$0$到$20$分不等。

    算法二:

    注意到每种状态实际上是可以压缩的。所以搜索的时候对于较小的数据把状态记录下来,用最小表示法去个重,对于稍大的数据可以用$IDA∗$搜索,对每个状态进行估价来进行加速。可以获得$20$到$40$分不等。

    算法三:

    将环上的问题转化为序列上,我们只需要将环复制一遍即可转化为序列。

    那么,考虑这样一个问题,对于最优解,一定存在一个点使得所有的交换都不经过这个点(它的左右不交换),下面简称这个点为断点。

    这样我们就可以枚举断点,答案即为把每个$B$挪到两端,反之同理。

    然后在进行统计答案,比较每一个断点哪个最优。

    现在来简单的证明一下断点的存在,来脑补一个环,环上面有很多$R$,我们肯定要将所有的$R$都撸到一起,而这时候,肯定存在“最下面一个点”作为底端,而在撸的时候肯定不会经过这个点。

    时间复杂度:$Theta (n^2)$。

    期望得分:$40$分。

    算法四:

    考虑决策的单调性问题,上面$Theta (n^2)$的算法中,我们需要再枚举一个点,这个点左端的$R$都移向左端,右端的都移向右端,那么就满足了一个$igcup$型函数。

    显然可以进行三分求解。

    那么当前枚举的区间的代价怎么求呢?

    我们需要开五个数组:

      $alpha.slft[i]$:表示将点$i$左侧所有的$R$都挪到最左端所要付出的代价,而每个$R$挪到最左端的代价就是它左端的$B$的数量。

      $eta.srht[i]$:表示将点$i$右侧所有的$R$都挪到最右端所要付出的代价。

      $chi.blft[i]$:表示点$i$左侧有几个$B$,可以感性的理解为$B$的左缀和。

      $delta.brht[i]$:表示点$i$右侧有几个$B$,可以感性的理解为$B$的右缀和。

      $epsilon.rlft[i]$:表示点$i$左侧有几个$R$,可以感性的理解为$R$的前缀和

    下面我只讲当前区间$[L,R]$下,将点$V$左侧的$R$都移到$L$所要付出的代价,反之同理:

      先写出来式子:$slft[V]-slft[L-1]-blft[L-1] imes (rlft[V]-rlft[L-1])$。

      来解释一下式子:

      $slft[V]-slft[L-1]$的含义为将$[L,V]$区间中所有的$R$移到最左端所要付出的代价,不过显然我们并不用把他们都移到左端,而是将其移动到$L$,那么我们不需要付出的代价就为$1$到$L$之间的$B$乘上$L$到$V$之间的$R$,即为$blft[L-1] imes (rlft[V]-rlft[L-1])$。

    时间复杂度:$Theta (nlog_{frac{3}{2}}n)$。

    期望得分:$65$分。

    算法五:

    我们还会发现这样一个问题,在断点不断右移的时候,当前状态的最有决策点肯定在上衣状态的最优决策点的右侧,这样复杂度就成了线性的了。

    时间复杂度:$Theta (n)$。

    期望得分:$100$分。


    代码时刻

    $Theta (nlog_{frac{3}{2}}n)$算法:

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    char ch[4000001];
    long long slft[4000001],srht[4000001],blft[4000001],brht[4000001],rlft[4000001];
    long long ans;
    long long minn(int x,int y,int z){return min(x,min(y,z));}
    long long judge(int l,int v,int r)
    {return slft[v]-slft[l-1]-blft[l-1]*(rlft[v]-rlft[l-1])+srht[v+1]-srht[r+1]-brht[r+1]*(rlft[r]-rlft[v]);}//计算答案
    long long _doudou(int l,int r)//三分
    {
    	int flagl=l,flagr=r;
    	while(r-l>2)
    	{
    		int midl=(r-l+1)/3+l;
    		int midr=(r-l+1)*2/3+l;
    		if(judge(flagl,midl,flagr)>judge(flagl,midr,flagr))l=midl;
    		else r=midr;
    	}
    	return minn(judge(flagl,l+1,flagr),judge(flagl,l,flagr),judge(flagl,r,flagr));
    }
    void pre_work()//清空
    {
    	for(int i=1;i<=n;i++)ch[n+i]=ch[i];
    	blft[0]=slft[0]=rlft[0]=srht[2*n+1]=brht[2*n+1]=0;
    }
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%s",ch+1);
    		ans=200209230020020923;
    		n=strlen(ch+1);
    		pre_work();
    		for(int i=1;i<=2*n;i++)
    		{
    			blft[i]=blft[i-1];
    			slft[i]=slft[i-1];
    			rlft[i]=rlft[i-1];
    			if(ch[i]=='B')blft[i]++;
    			else
    			{
    				rlft[i]++;
    				slft[i]+=blft[i];
    			}
    		}
    		for(int i=2*n;i;i--)
    		{
    			brht[i]=brht[i+1];
    			srht[i]=srht[i+1];
    			if(ch[i]=='B')brht[i]++;
    			else srht[i]+=brht[i];
    		}
    		for(int i=1;i<=n;i++)
    			ans=min(ans,_doudou(i,i+n-1));
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    

    $Theta (n)$算法:

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    char ch[4000001];
    long long slft[4000001],srht[4000001],blft[4000001],brht[4000001],rlft[4000001];
    long long ans;
    long long judge(int l,int v,int r)
    {return slft[v]-slft[l-1]-blft[l-1]*(rlft[v]-rlft[l-1])+srht[v+1]-srht[r+1]-brht[r+1]*(rlft[r]-rlft[v]);}
    void pre_work()
    {
    	for(int i=1;i<=n;i++)ch[n+i]=ch[i];
    	blft[0]=slft[0]=rlft[0]=srht[2*n+1]=brht[2*n+1]=0;
    }
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%s",ch+1);
    		ans=200209230020020923;
    		n=strlen(ch+1);
    		pre_work();
    		for(int i=1;i<=2*n;i++)
    		{
    			blft[i]=blft[i-1];
    			slft[i]=slft[i-1];
    			rlft[i]=rlft[i-1];
    			if(ch[i]=='B')blft[i]++;
    			else
    			{
    				rlft[i]++;
    				slft[i]+=blft[i];
    			}
    		}
    		for(int i=2*n;i;i--)
    		{
    			brht[i]=brht[i+1];
    			srht[i]=srht[i+1];
    			if(ch[i]=='B')brht[i]++;
    			else srht[i]+=brht[i];
    		}
    		int lft=1;
    		for(int i=1;i<=n;i++)
    		{
    			while(lft!=n+i&&judge(i,lft,i+n-1)>=judge(i,lft+1,i+n-1))lft++;
    			ans=min(ans,judge(i,lft,i+n-1));
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    

    rp++

  • 相关阅读:
    默认组件加载类
    加密工具类
    客户端安全传输密码至服务端的实现改进
    开发Angular库的简单指导(译)
    Windows中搭建Redis集群
    Mybatis中SqlMapper配置的扩展与应用(3)
    Mybatis中SqlMapper配置的扩展与应用(2)
    Mybatis中SqlMapper配置的扩展与应用(1)
    优化与扩展Mybatis的SqlMapper解析
    使用XSD校验Mybatis的SqlMapper配置文件(2)
  • 原文地址:https://www.cnblogs.com/wzc521/p/11246907.html
Copyright © 2011-2022 走看看