ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AtCoder Beginner Contest 212题解

2021-08-04 19:33:56  阅读:149  来源: 互联网

标签:AtCoder ch 212 int 题解 sum && 操作


前言

好久没有打ABC了 ,上一次打已经是ABC196了,震惊这次有8题,世界第一也来了,30min就全切了,可惜我只会ABCD。

upd:我好像会E了。

Alloy

题目大意

给两个数,要判断这两个数在哪个范围,范围就不用解释了吧······

题解

直接if判断即可,非常简单。

代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a,b;
	cin>>a>>b;
	if(a==0&&b>0)puts("Silver");
	if(a>0&&b==0)puts("Gold");
	if(a>0&&b>0)puts("Alloy");
	return 0;
} 

Weak Password

题目大意

给一个数字的 PIN,要判断这个 PIN 的强弱,如果出现下面两种情况之一,就算弱:

  • 四位相同,见样例一。
  • 每相邻两位递增\(1\),如\(0\)后接着\(1\),\(1\)后接着\(2\),注意\(9\)后接着\(0\),见样例三。

题解

对于判定\(1\),直接if判断即。

对于判定\(2\),扫一遍数列合不合法,因为\(9\)后接着\(0\),所以要特别判定一下,当然也可以直接与\(10\)取余。

输入时用字符串处理比较方便,注意数组下标从\(0\)开始。

代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
	char ch[5];
	bool flag;
	cin>>ch;
	if(ch[0]==ch[1]&&ch[1]==ch[2]&&ch[2]==ch[3])
	{
		puts("Weak");
		return 0;
	}
	flag=true;
	for(int i=0;i<=2;i++)
		if(ch[i+1]-'0'!=(ch[i]-'0'+1)%10)
		{
			flag=false;
			break;
		}	
	if(flag==true)puts("Weak");
	else puts("Strong");
	return 0;
} 

Min Difference

题目大意

已知两个数列\(A\)和\(B\),求:

\[\min|A_i-B_j|(1\le i\le n,1\le j\le m) \]

题解

很明显有\(O(nm)\)的暴力,可过不了这道题,考虑优化。

对于答案,我们只寻找差的绝对值较小的,而不用关心差的绝对值一定大的数,因此对于每个数而言,其实只用计算比自己大和自己小的离自己最近的两个数即可。

所以我们先将两个数列排序,再解决上面的问题。

但如何解决使两个数差距尽可能小呢?可以使用双指针\(i\)和\(j\)表示\(A_i\)和\(B_j\),我们要先思考:如果知道\(A_i\)和\(B_j\)的大小关系,是增加\(i\)还是增加\(j\)更对答案有贡献。

这要分成两种情况(注意已经按升序排好):

  • \(A_i>B_j\),这时候增加\(j\),因为增加\(i\)只会使两个数差距越来越大。
  • \(A_i\le B_j\),这时候增加\(i\),因为增加\(j\)只会使两个数差距越来越大。

注意两个指针会遍历两个数列,所以遍历的时间复杂度为\(O(n+m)\),加上排序,总时间为\(O(n\log n+m\log m)\)。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+7;
int a[N],b[N];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=m;i++)scanf("%d",&b[i]);
    sort(a+1,a+n+1);
    sort(b+1,b+m+1);
    int ans=INT_MAX;
    for(int i=1,j=1;i<=n&&j<=m;)
    {
        ans=min(ans,abs(a[i]-b[j]));
        if(a[i]>b[j]) j++;
        else i++;
    }
    printf("%d",ans);
    return 0;
}

Querying Multiset

题目大意

维护一个包?数据结构,满足以下三种操作:

  • 在一个空球上面写一个整数\(X\),并把这个球放入包内。
  • 对于包内的所有球,将每个球上面的整数加上\(X\)。
  • 输出包中所有球上的最小的数字,并把这个球扔掉.

题解

对于这种带加入删除的整体最大最小值问题,很明显就是堆,对于这道题,只要维护一个小根堆。

因为操作\(2\)不可能将所有数都暴力模拟,但对于同一基准的数,不管加上多少,数的大小关系总不变,因此我们来解决如何把数都变成同一标准。

先记录一下操作\(2\)加了多少,记为\(sum\),这样每个数就可以表示为\(a_i+sum\)(\(a_i\)为同一基准数)。

先不考虑操作\(3\),对于每次操作\(1\),将\(X-sum\)就可以将加入的数\(X\)与堆中的其他数变成同一标准,因为这个数加入之前的操作\(2\)的值与这个数是无关的,如果还不明白,那就举个例子:

假设现在只有一个数\(X\),进行了一次操作\(2\),所加总和记为\(sum\)。

进行了一次操作\(1\),加入了一个数\(Y-sum\)。

又进行了一次操作\(2\),加上了一个数\(k\),所加总和记为\(sum+k\)。

此时\(X\)的值为\(X+sum+k\),\(Y\)的值为\(Y-sum+sum+k=Y+k\)。

操作\(2\)很简单,直接将\(sum+X\)就可以了。

操作\(3\)的话也很简单,直接取队头的值\(a_{top}+sum\)就可以了。

注意开long long,时间复杂度为\(O(n\log n)\)。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n;
priority_queue<LL,vector<LL>,greater<LL> > heap;
LL sum;
int main()
{
    scanf("%d",&n);
    while(n--){
        int op,x;
        scanf("%d",&op);
        if(op==1){
            scanf("%d",&x);
            heap.push(x-sum);
        }
        else if(op==2){
            scanf("%d",&x);
            sum+=x;
        }
        else{
            printf("%lld\n",heap.top()+sum);
            heap.pop();
        }
    }
    return 0;
}

标签:AtCoder,ch,212,int,题解,sum,&&,操作
来源: https://www.cnblogs.com/qinchenhao/p/15100443.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有