AtCoder Beginner Contest 181 题解

总结

第一次 \(AK\ ABC\) 的比赛,发一个截图纪念一下

A - Heavy Rotation

题目大意

一个人一开始穿白衣服,一天后换成黑衣服,再过一天又换成白衣服,问第 \(n(n \leq 30)\) 天这个人穿什么颜色的衣服

分析

\(n\) 为奇数时输出 \(Black\),否则输出 \(White\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define rg register
inline int read(){
	rg int x=0,fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=1e5+5;
int main(){
	int n;
	scanf("%d",&n);
	if(n&1) printf("Black\n");
	else printf("White\n");
	return 0;
}

B - Trapezoid Sum

题目大意

给出 \(n(1 \leq n \leq 10^5)\) 次操作
每次操作加上 \(a \sim b(1 \leq a \leq b \leq 10^6)\) 这个区间内所有数之和
问最终的答案是多少

分析

用等差数列求和公式即可解决

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define rg register
inline int read(){
	rg int x=0,fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=1e5+5;
int n;
int main(){
	n=read();
	long long sum=0;
	rg int aa,bb;
	for(rg int i=1;i<=n;i++){
		aa=read(),bb=read();
		sum+=1LL*(aa+bb)*(bb-aa+1)/2LL;
	}
	printf("%lld\n",sum);
	return 0;
}

C - Collinearity

题目大意

\(n\) 个点,第 \(i\) 个点坐标为 \((x_i,y_i)\),判断是否存在三点共线。
\(3≤n≤100,|x_i|,|y_i|≤10^3\),任意两点坐标均不相同。

分析

每次取出两个点,求出直线的解析式,再从其他点中找有没有符合这个解析式的
要把横坐标相等的特判一下

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define rg register
inline int read(){
	rg int x=0,fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=1e2+5;
int n,x[maxn],y[maxn];
std::map<int,int> mp;
int main(){
	n=read();
	bool jud=0;
	for(rg int i=1;i<=n;i++){
		x[i]=read(),y[i]=read();
	}
	for(rg int i=1;i<=n;i++){
		for(rg int j=i+1;j<=n;j++){
			if(x[i]==x[j]) continue;
			double k=(double)(y[i]-y[j])/(x[i]-x[j]);
			double b=y[i]-k*x[i];
			rg int cnt=2;
			for(rg int kk=1;kk<=n;kk++){
				if(i==kk || j==kk) continue;
				if(x[kk]*k+b==y[kk]) cnt++;
			}
			if(cnt>=3) jud=1;
		}
	}
	for(rg int i=1;i<=n;i++){
		mp[x[i]]++;
		if(mp[x[i]]>=3) jud=1;
	}
	if(jud) printf("Yes\n");
	else printf("No\n");
	return 0;
}

D - Hachi

题目大意

给一个长度为 \(s\) 的数字,判断这个数字在任意交换数位后是否存在一个可以被 \(8\) 整除的数。
\(1≤s≤200000\),每位数字均在 \([1,9]\) 之间。

分析

要判断一个数字能否被 \(8\) 整除,只需要判断它的后三位能否被 \(8\) 整除
因为 \(1000\) 的倍数肯定是 \(8\) 的倍数
那么我们只要从 \(0\)\(1000\) 枚举 \(8\) 的倍数,判断从给定的数字中选取一些数能否组成 \(8\) 的倍数即可
要把长度小于 \(3\) 的数字特判一下

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define rg register
inline int read(){
	rg int x=0,fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=1e6+5;
char s[maxn];
int len,cnt[maxn],ncnt[maxn],ans,a[maxn];
int main(){
	scanf("%s",s+1);
	len=strlen(s+1);
	bool jud=0;
	if(len<=3){
		int mi=1,nans=0;
		for(rg int i=1;i<=len;i++){
			a[i]=s[i]-'0';
		}
		std::sort(a+1,a+1+len);
		while(1){
			mi=1;
			nans=0;
			for(rg int j=1;j<=len;j++){
				nans+=a[j]*mi;
				mi*=10;
			}
			if(nans%8==0) jud=1;
			if(std::next_permutation(a+1,a+1+len)==0) break;
		}
	} else {
		for(rg int i=1;i<=len;i++){
			cnt[s[i]-'0']++;
		}
		for(rg int i=100;i<=1000;i++){
			if(i%8) continue;
			for(rg int j=0;j<=9;j++) ncnt[j]=0;
			rg int now=i;
			while(now){
				ncnt[now%10]++;
				now/=10;
			}
			bool pd=1;
			for(rg int j=0;j<=9;j++){
				if(cnt[j]<ncnt[j]) pd=0;
			}
			if(pd) jud=1;
		}
	}
	if(jud) printf("Yes\n");
	else printf("No\n");
	return 0;
}

E - Transformable Teacher

题目大意

\(n\)\(n\) 为奇数) 个小朋友和 \(m\)个老师,每个人都有自己的权值。
现在要选出 \(1\) 位老师给小朋友们上课,并将小朋友们两两分组。
请选出一个选老师和分组的方案,使得所有组两人权值之差的绝对值之和最小。

分析

显然排序之后的答案一定是最小的
那么我们可以先将所有的小朋友按照身高从小到大排好序
对于每一位老师,二分枚举他的位置
因为老师的插入最多只会改变两组小朋友的匹配
所以我们要预处理出从第一个小朋友开始匹配的答案的前缀和以及从第二个小朋友开始匹配的答案的前缀和
这样就可以 \(O(1)\) 计算答案

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define rg register
inline int read(){
	rg int x=0,fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=1e6+5;
int h[maxn],w[maxn],n,m;
long long sum1[maxn],sum2[maxn];
int main(){
	n=read(),m=read();
	for(rg int i=1;i<=n;i++){
		h[i]=read();
	}
	std::sort(h+1,h+1+n);
	for(rg int i=1;i<=m;i++){
		w[i]=read();
	}
	for(rg int i=1;i<=n/2;i++){
		sum1[i]=sum1[i-1]+h[i*2]-h[i*2-1];
	}
	for(rg int i=1;i<=n/2;i++){
		sum2[i]=sum2[i-1]+h[i*2+1]-h[i*2];
	}
	rg long long ans=0x3f3f3f3f3f3f3f3f;
	for(rg int i=1;i<=m;i++){
		if(w[i]>h[n]){
			ans=std::min(ans,w[i]-h[n]+sum1[n/2]);
		} else {
			rg int wz=std::upper_bound(h+1,h+1+n,w[i])-h;
			if(wz&1) ans=std::min(ans,sum1[wz/2]+h[wz]-w[i]+sum2[n/2]-sum2[wz/2]);
			else ans=std::min(ans,sum1[(wz-1)/2]+w[i]-h[wz-1]+sum2[n/2]-sum2[(wz-1)/2]);
		}
	}
	printf("%lld\n",ans);
	return 0;
}

F - Silver Woods

题目大意

平面上有 \(n\) 个点,现在你有一个半径待定的圆,且初始时圆心位于 \((−10^9,0)\)
你需要最大化圆的半径,且满足这个圆能穿通过移动,直到圆心到达 \((10^9,0)\)
在移动的过程中圆不能与直线 $y=10$0
或直线 \(y=−100\) 相交,且任何时候这 \(n\)个点都不在圆内。
\(n≤100,|xi|,|yi|≤100\)

分析

二分圆的半径,利用并查集维护距离小于等于当前二分的答案的点的集合
对于每一个集合,判断其是否将道路封住
如果没有就合法,否则不合法

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define rg register
inline int read(){
	rg int x=0,fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=1e3+5;
typedef double db;
const db eps=1e-10;
db x[maxn],y[maxn],dis[maxn][maxn],mmin[maxn],mmax[maxn];
int n,fa[maxn];
int zhao(int xx){
	if(xx==fa[xx]) return xx;
	return fa[xx]=zhao(fa[xx]);
}
bool jud(db val){
	for(rg int i=1;i<=n;i++){
		fa[i]=i;
		mmin[i]=std::max(-100.0,y[i]-val*2.0);
		mmax[i]=std::min(100.0,y[i]+val*2.0);
	}
	for(rg int i=1;i<=n;i++){
		for(rg int j=i+1;j<=n;j++){
			rg int aa=zhao(i),bb=zhao(j);
			if(aa==bb) continue;
			if(dis[i][j]>2.0*val) continue;
			fa[bb]=aa;
			mmin[aa]=std::min(mmin[aa],mmin[bb]);
			mmax[aa]=std::max(mmax[aa],mmax[bb]);
		}
	}
	for(rg int i=1;i<=n;i++){
		if(fa[i]==i){
			if(mmin[i]==-100.0 && mmax[i]==100.0) return 0;
		}
	}
	return 1;
}
int main(){
	scanf("%d",&n);
	for(rg int i=1;i<=n;i++){
		scanf("%lf%lf",&x[i],&y[i]);
	}
	for(rg int i=1;i<=n;i++){
		for(rg int j=1;j<=n;j++){
			dis[i][j]=(db)sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
		}
	}
	rg db l=0.0,r=100.0,mids;
	while(r-l>eps){
		mids=(l+r)/2.0;
		if(jud(mids)) l=mids;
		else r=mids;
	}
	printf("%.6f\n",mids);
	return 0;
}
posted @ 2020-11-05 11:46  liuchanglc  阅读(257)  评论(2)    收藏  举报