【赛时总结】 ◇赛时·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

相关文章
相关标签/搜索