[CSP-S模擬測試]:壽司(暴力)

題目描述

小$c$是一名$oier$。最近,他發現他的數據結構好像學傻了。由於他在刷題時碰到了一道傻逼數據結構題,強行使用了平衡樹來解決,卡着時間$AC$。爲此,他被狠狠地嘲諷了一番。因而,小$c$找了大量的數據結構題來作。c++

昨天,小$c$正在吃壽司,忽然發現許多盤壽司圍成了一個圓圈,這些壽司中有紅色的也有藍色的。因爲小$c$看交錯的顏色很是不爽,想經過一些操做,使得全部的紅色壽司造成了一塊連續的區域,藍色的壽司也造成了一塊連續的區域。若是小$c$每次只能夠交換相鄰的兩盤壽司,那麼最少須要多少步才能夠達到小$c$的要求呢?因爲他作題作多了,腦殼已經有點不清醒了,因而這個問題就交給你了。算法


輸入格式

第一行一個數$T$,表示數據組數。
接下來$T$行,每行一行由$B$和$R$組成的字符串,$B$表示藍色,$R$表示紅色。第$i$個字符描述順時針數第$i$盤壽司的顏色。注意,最後一盤壽司和第$1$盤壽司是相鄰的。
數組


輸出格式

對於每組數據,輸出一行表示最小的交換次數。數據結構


樣例

樣例輸入函數

1
BBRBBRBBBRRR
spa

樣例輸出blog

5字符串


數據範圍與提示

樣例說明:it

如下說明交換的步驟:
交換位置$2$、位置$3$上的壽司;
交換位置$1$、位置$2$上的壽司;
交換位置$6$、位置$7$上的壽司;
交換位置$7$、位置$8$上的壽司;
交換位置$8$、位置$9$上的壽司;
class

數據範圍:

$T\leqslant 10$

$n\leqslant 1,000,000$


題解

算法一:

爆搜,枚舉全部走法。能夠得到$0$到$20$分不等。

算法二:

注意到每種狀態其實是能夠壓縮的。因此搜索的時候對於較小的數據把狀態記錄下來,用最小表示法去個重,對於稍大的數據能夠用$IDA∗$搜索,對每一個狀態進行估價來進行加速。能夠得到$20$到$40$分不等。

算法三:

將環上的問題轉化爲序列上,咱們只須要將環複製一遍便可轉化爲序列。

那麼,考慮這樣一個問題,對於最優解,必定存在一個點使得全部的交換都不通過這個點(它的左右不交換),下面簡稱這個點爲斷點。

這樣咱們就能夠枚舉斷點,答案即爲把每一個$B$挪到兩端,反之同理。

而後在進行統計答案,比較每個斷點哪一個最優。

如今來簡單的證實一下斷點的存在,來腦補一個環,環上面有不少$R$,咱們確定要將全部的$R$都擼到一塊兒,而這時候,確定存在「最下面一個點」做爲底端,而在擼的時候確定不會通過這個點。

時間複雜度:$\Theta (n^2)$。

指望得分:$40$分。

算法四:

考慮決策的單調性問題,上面$\Theta (n^2)$的算法中,咱們須要再枚舉一個點,這個點左端的$R$都移向左端,右端的都移向右端,那麼就知足了一個$\bigcup$型函數。

顯然能夠進行三分求解。

那麼當前枚舉的區間的代價怎麼求呢?

咱們須要開五個數組:

  $\alpha.slft[i]$:表示將點$i$左側全部的$R$都挪到最左端所要付出的代價,而每一個$R$挪到最左端的代價就是它左端的$B$的數量。

  $\beta.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]\times (rlft[V]-rlft[L-1])$。

  來解釋一下式子:

  $slft[V]-slft[L-1]$的含義爲將$[L,V]$區間中全部的$R$移到最左端所要付出的代價,不過顯然咱們並不用把他們都移到左端,而是將其移動到$L$,那麼咱們不須要付出的代價就爲$1$到$L$之間的$B$乘上$L$到$V$之間的$R$,即爲$blft[L-1]\times (rlft[V]-rlft[L-1])$。

時間複雜度:$\Theta (n\log_{\frac{3}{2}}n)$。

指望得分:$65$分。

算法五:

咱們還會發現這樣一個問題,在斷點不斷右移的時候,當前狀態的最有決策點確定在上衣狀態的最優決策點的右側,這樣複雜度就成了線性的了。

時間複雜度:$\Theta (n)$。

指望得分:$100$分。


代碼時刻

$\Theta (n\log_{\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\n",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\n",ans);
	}
	return 0;
}

rp++

相關文章
相關標籤/搜索