【賽時總結】 ◇賽時·I◇ AtCoder ARC-098

◆賽時I◆ ARC-098


■試題&解析■

◆本場最水◆ C-Attention

長點兒信心吧……算法

  • 【AtCoder ARC-098 C】數組

  • 【解析】 既然只存在左右(東西)兩個朝向,那麼領導右側的人應朝左,相反左側的人朝右。則要找到一我的做爲領導使上述人的數量最多。 咱們能夠用 tot[0]、tot[1] 分別儲存最初朝東、西的人的個數。而後從第一我的開始枚舉,統計當前人左側的分別朝向東、西的人的個數,從而算出當前人左側朝右、右側朝左的人的個數,記爲F。領導人便是算出F最大的人。 注意統計時要排開當前人的數量(領導人不算在內,不須要改變朝向)。spa

  • 【源代碼】code

/*Lucky_Glass*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN int(3*1e5)
int len,tot[2],res[2],ans;
char s[MAXN+5];
int main()
{
	scanf("%d%s",&len,s);
	for(int i=0;i<len;i++)
		tot[s[i]=='E']++;
	ans=1e9;
	for(int i=0;i<len;i++)
	{
		int F=0;
		F+=res[0];
		F+=tot[1]-res[1]-int(s[i]=='E');
		res[s[i]=='E']++;
		ans=min(ans,F);
	}
	printf("%d\n",ans);
	return 0;
}

◆腦袋開竅◆ D-Xor Sum 2

沒辦法,做者就是腦袋不開竅啊 QwQget

  • 【AtCoder ARC-098 D】
  • 【解析】 其實這道題我沒有看出來我哪裏TLE了,和正解的算法同樣——滑動窗口,多是寫的醜吧。

對於異或有一個技巧——若是 A^B==A+B ,則 A&B==0 即A、B的二進制的各個數位都不相同。如今問題就變成尋找一個區間 [l,r] 使得 Ai&Aj=0 (i≠j 且 l≤i,j≤r)。string

定義區間左右端點l、r,並初始化l=1,r=0。保證 r < n(即 r+1≤n 且 l≤r )。定義當前區間的全部數異或所獲得的值爲F,初始化爲0。 若 A[r+1]&F==0 即當前區間向右擴充1後,仍然知足所給條件,則更新F、r,向右擴充,並同時更新ans,增長的答案個數爲擴充後區間的長度。用while循環執行此操做。 第一次while循環結束後,則要麼枚舉完了,要麼 F&A[r+1]!=0 ,此時不管如何向右擴充都沒法知足題目所給條件,因此只能刪除左側,直到再次知足 F&A[r+1]==0 (當區間爲空時,也知足 F&A[r+1]==0 )。 注意:ans用 long long 儲存。it

  • 【源代碼】
/*Lucky_Glass*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=2*1e5;
int n,A[MAXN+5];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&A[i]);
	int l=1,r=0,F=0;
	long long ans=0;
	while(r<n)
	{
		while(r<n && !(F&A[r+1]))
		{
			r++;ans+=r-l+1;
			F^=A[r];
		}
		while(l<=r && (F&A[r+1]))
			F^=A[l++];
	}
	printf("%lld\n",ans);
	return 0;
}

◆想不到吧◆ E - Range Minimum Queries

這個是真的想不到 (u_u)io

  • 【AtCoder ARC-098 E】
  • 【解析】 對答案有影響的變量主要是最大值和最小值,那麼就能夠先經過枚舉限制其中一個變量(這裏我用最小值)。 限制最小值,也就是說枚舉Ai,在選取區間時,區間中最小的元素不能小於Ai。這樣咱們就能夠將 A 分紅多個段——每一個段中的元素都大於等於Ai。這樣就限制了區間中取到的最小值,可是此時的最小值不必定是Ai(好比枚舉到的Ai=2,則當k=2時數據「1 2 1」就取不到2)。最小值肯定後,要使最大值減最小值最小,則須要讓最大值儘可能小,即抽取到的數要儘可能小。 那麼咱們能夠提取出各個知足長度大於等於k的段。這些段能夠做爲選取區間的段,且設段的長度爲len,咱們能夠在這個段裏取 len-k+1 次區間(每一次選取都會使段的長度減小1,直到區間長度小於k)。可見若是取 len-k+1 次區間,則必定能夠取出這個段裏前 len-k+1 小的數。 爲了使取出的數儘可能小,咱們須要儘可能使每一個段中取出的數都儘可能小,也就是段中前 len-k+1 小的數。咱們能夠將這些數存入另一個數組(pri),方便最後找到最小的最大值。因爲咱們要進行Q次抽取,最小的最大值必定是 pri 中第 Q 小的數,而最小值就是 pri 中最小的數。
  • 【源代碼】
/*Lucky_Glass*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN=2000;
const int INF=(int)1e9+5;
int n,k,q,A[MAXN+5],ans=INF;
void SOLVE(int x)
{
	vector<int> pri;
	int i=0;
	while(i<n)
	{
		vector<int> que;
		while(A[i]<x && i<n) i++;
		while(A[i]>=x && i<n) que.push_back(A[i++]);
		if(que.size()>=k)
		{
			sort(que.begin(),que.end());
			for(int j=0;j<(int)que.size()-k+1;j++)
				pri.push_back(que[j]);
		}
	}
	sort(pri.begin(),pri.end());
	if((int)pri.size()>=q)
		ans=min(ans,pri[q-1]-pri[0]);
}
int main()
{
	scanf("%d%d%d",&n,&k,&q);
	for(int i=0;i<n;i++)
		scanf("%d",&A[i]);
	for(int i=0;i<n;i++)
		SOLVE(A[i]);
	printf("%d\n",ans);
	return 0;
}

(F題真的不會作了,請各位神牛多多指點)class


The End

Thanks for reading!

-Lucky_Glasstest

相關文章
相關標籤/搜索