AtCoder Beginner Contest 215 个人题解
比赛链接:AtCoder Beginner Contest 215
更好的阅读体验:戳这里@不会飞的小飞龙
前言:这是小飞龙在AtCoder的的一场比赛
AtCoder题面好评!简单明了,丝毫没有拖泥带水,这让英文水平菜的一批的小飞龙很是欣慰o( ̄▽ ̄)ブ
A题 Your First Judge
题目大意:
一句话题意,给出一串字符串,判断是否和Hello,World!
完全匹配,如果是输出AC
,否则输出WA
思路解析:
难度高于且仅高于输出hello world!
(也就是符合小飞龙目前水平的题)
AC代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
cin>>s;
cout<<(s=="Hello,World!"?"AC":"WA")<<endl;
}
B题 log2(N)
题目大意:
给出一个数 $n$ , $1<=n<=10^{18}$ ,输出 $log_2(n)$
思路解析:
直接模拟乘 $2$ 即可(直接用Math
库的 $log_2()$ 有 $WA$ 的风险,具体反面教材 @tbw)
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
ll n,now=1;
cin>>n;
for(ll i=1;;i++){
now*=2;
if(now>n){
cout<<i-1<<endl;
break;
}
}
}
C题 One More aab aba baa
题目大意:
给出一串字符串 $S$ 和它的长度,输出字典序第 $K$ 小的字符串排列
思路解析:
由于我们可以看到 $1<=|S|<=8$ ,所以我们可以对 $S$ 排序后直接用 $STL$ 中的next_permutation()
来枚举他的排列,输出第 $K$ 小排列即可
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int n;
char s[maxn];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>s>>n;
int sz=strlen(s),sum=0;
sort(s,s+sz);
do{
sum++;
if(sum==n){
for(int i=0;i<sz;i++)cout<<s[i];
break;
}
}
while(next_permutation(s,s+sz));
}
D题 Coprime 2
题目大意:
给出一长度为 $N$ 的序列 $A_i$ ,和一个正整数 $M$ ,我们需要找到所有的 $k$ 且同时满足 $1<=k<=M$ 且 $gcd(A_i,k)=1(1<=i<=N)$
思路解析:
根据题意我们可以发现,我们需要的k和数组中的每一个元素的 $gcd$ 都为 $1$ ,所以我们很容易想到从序列中每一个数的约数下手,可是我们处理完约数后该怎么办呢?
这时候,我们很容易想到,对于每一个约数以及约数的倍数,都一定不可能作为我们 $k$ 的候选值,我们要做的就是在 $1-M$ 中刨除这些数,是不是感觉在哪里见过?确实,这就是我们晒素数使用的线性筛,可以使我们这道题的复杂度大大降低(具体反面教材再次 @tbw)
另外,对于序列中的所有约数我们可以判一下重后再处理,因为他的玩味并不是很大,所以显然约数的数量并不是很大,所以复杂度并不高
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int vis[maxn],p[maxn];
int st[maxn];
vector<int> get_divisiors(int n)
{
vector<int> res;
for(int i = 1; i <= n / i; i ++ )
if(n % i == 0)
{
res.push_back(i);
if(i != n / i) res.push_back(n / i);
}
sort(res.begin(), res.end());
return res;
}
vector<int >ans[maxn];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,m,op;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>op;
ans[i]=get_divisiors(op);
for(int k=0;k<ans[i].size();k++){
if(ans[i][k]==1)continue;
if(st[ans[i][k]])continue;
st[ans[i][k]]=1;
for(int j=ans[i][k];j<=m;j+=ans[i][k]){
if(vis[j])continue;
vis[j]=1;
}
}
}
int top=0;
for(int i=1;i<=m;i++)if(!vis[i])p[++top]=i;
cout<<top<<endl;
for(int i=1;i<=top;i++)cout<<p[i]<<endl;
}
E题 Chain Contestant
队友写了我就不写了(逃)
戳这里查看题解 @tbw831
F题 Dist Max 2
题目大意:
给出平面内n个点的坐标,定义两点之间的距离为 $min(|x_i-x_j|,|y_i-y_j|)$ ,输出两个不同点的距离的最大值
思路解析:
从问题来看,求 $min$ 的最大值,很容易想到用二分答案来解决这道题,这样问题就转化为了判定所有点中是否存在两个不同点满足距离大于等于 $mid$ ,二分即可
那么如何判定是否存在呢?我们可以用单调队列来判断,复杂度 $O(n)$ ,总复杂度 $O(nlogn)$
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int maxn=1e5+5;
vector<pii>a;
int check(int mid){
queue<pii>q;
int minn=1e9+7,maxx=0;
for(int i=0;i<a.size();i++){
while(q.size()){
if(q.front().first>a[i].first-mid)break;
minn=min(minn,q.front().second);
maxx=max(maxx,q.front().second);
q.pop();
}
if(minn<=a[i].second-mid||maxx>=a[i].second+mid)return 1;
q.push(a[i]);
}
return 0;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n;
cin>>n;
for(int i=1;i<=n;i++){
int x,y;
cin>>x>>y;
a.push_back({x,y});
}
sort(a.begin(),a.end());
int l=0,r=1e9+7;
while(l < r){
int mid=l+r+1>>1;
if(check(mid))l=mid;
else r = mid - 1;
}
cout<<l<<endl;
}
qp qp qp qp