【题解】AtCoder Beginner Contest 239

A - Horizon

题面

给定一个 x ,输出 \(\sqrt{x(x+12800000)}\)

思路

精度要求过低,直接输出即可

代码

//吾日八省吾身:
//输入多而不快读乎?
//题目标注而不freopen乎?
//乘除并列先乘后除乎?
//不手撕样例直接写代码乎?
//不仔细读题直接关页面乎?
//1e9而不开long long乎?
//Ctrl+V而不改名称乎?(papaw->papan IMPLIES tg1=->2=)
//相信评测神机乎?
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<utility>
#include<deque>
#include<ctime>
#include<sstream>
#include<list>
#include<bitset>
using namespace std;
typedef long long ll;
ll H;
int main(){
	cin>>H;
	printf("%.6lf\n",sqrt(H*(H+12800000)));
	return 0;
} 

B - Integer Division

题面

给定一个 x ,输出 \(\left \lfloor \frac{x}{10} \right \rfloor\)

思路

注意到是向下取整,所以判一判 x 是 10 的倍数的情况就好啦

代码

//吾日八省吾身:
//输入多而不快读乎?
//题目标注而不freopen乎?
//乘除并列先乘后除乎?
//不手撕样例直接写代码乎?
//不仔细读题直接关页面乎?
//1e9而不开long long乎?
//Ctrl+V而不改名称乎?(papaw->papan IMPLIES tg1=->2=)
//相信评测神机乎?
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<utility>
#include<deque>
#include<ctime>
#include<sstream>
#include<list>
#include<bitset>
using namespace std;
typedef long long ll;
ll H;
int main(){
	cin>>H;
	if(!(H%10)) printf("%lld\n",H/10);
	else printf("%lld\n",H/10+(-1)*(H<0));
	return 0;
} 

C - Knight Fork

题面

给你两个点的坐标,问是否存在一个点使得该点到两点的距离都为 \(\sqrt{5}\)

思路

考虑到距离为 \(\sqrt{5}\) 的两个点只可能是一个坐标轴上差 1 ,另一个差 2 ,直接枚举可能的点,再枚举距离另一个点为 \(\sqrt{5}\) 的点,判断两次枚举是否有重合即可。

代码

//吾日八省吾身:
//输入多而不快读乎?
//题目标注而不freopen乎?
//乘除并列先乘后除乎?
//不手撕样例直接写代码乎?
//不仔细读题直接关页面乎?
//1e9而不开long long乎?
//Ctrl+V而不改名称乎?(papaw->papan IMPLIES tg1=->2=)
//相信评测神机乎?
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<utility>
#include<deque>
#include<ctime>
#include<sstream>
#include<list>
#include<bitset>
using namespace std;
typedef long long ll;
ll xx1,yy1,xx2,yy2;
ll ans[233][33],cnt,rere=0;
void doit(ll x,ll y){
	ans[++cnt][1]=xx1+x;
	ans[cnt][2]=yy1+y;
	return;
}
bool findit(ll x,ll y){
	for(ll i=1;i<=cnt;++i) if((xx2+x)==ans[i][1]&&(yy2+y)==ans[i][2]) return true;
	return false;
}
int main(){
	cin>>xx1>>yy1>>xx2>>yy2;
	for(ll x=1;x<=2;++x){
		for(ll fx=-1;fx<=1;++fx,++fx){
			ll y=(x==1?2:1);
			for(ll fy=-1;fy<=1;++fy,++fy)
				doit(x*fx,y*fy);
		}
	}for(ll x=1;x<=2;++x){
		for(ll fx=-1;fx<=1;++fx,++fx){
			ll y=(x==1?2:1);
			for(ll fy=-1;fy<=1;++fy,++fy)
				rere+=findit(x*fx,y*fy);
		}
	}
	if(rere) printf("Yes\n");
	else printf("No\n");
	return 0;
} 

D - Prime Sum Game

题面

小T先在 \(A\sim B\) 中选择一个数,小A再在 \(C\sim D\) 中选择一个数,如果两个数之和为质数则小A赢,否则小T赢。

思路

无需和它死磕,范围很小,直接枚举小T的每种取值能不能赢即可。

代码

//吾日八省吾身:
//输入多而不快读乎?
//题目标注而不freopen乎?
//乘除并列先乘后除乎?
//不手撕样例直接写代码乎?
//不仔细读题直接关页面乎?
//1e9而不开long long乎?
//Ctrl+V而不改名称乎?(papaw->papan IMPLIES tg1=->2=)
//相信评测神机乎?
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<utility>
#include<deque>
#include<ctime>
#include<sstream>
#include<list>
#include<bitset>
using namespace std;
typedef long long ll;
ll a,b,c,d;
bool ipr(ll fafa){
	if(fafa==1) return false;
	if(fafa==2||fafa==3||fafa==5||fafa==7||fafa==11) return true;
	ll lim=sqrt(fafa)+1;
	for(ll i=2;i<=lim;++i) if(fafa%i==0) return false;
	return true;
}
bool takahashi(ll num){
	for(ll i=c;i<=d;++i)
		if(ipr(num+i)) return false;
	return true;
}
int main(){
	cin>>a>>b>>c>>d;
	for(ll i=a;i<=b;++i){
		if(takahashi(i)){
			printf("Takahashi\n");
			return 0;
		}
	}
	printf("Aoki\n");
	return 0;
} 

E - Subtree K-th Max

题面

给定一棵树,点有点权,1 号点为根,每次询问以某个点为根的子树内第 k 大的点权是多少。

思路

k 很小,开数组记录并暴力合并子树答案即可。

代码

//吾日八省吾身:
//输入多而不快读乎?
//题目标注而不freopen乎?
//乘除并列先乘后除乎?
//不手撕样例直接写代码乎?
//不仔细读题直接关页面乎?
//1e9而不开long long乎?
//Ctrl+V而不改名称乎?(papaw->papan IMPLIES tg1=->2=)
//相信评测神机乎?
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<utility>
#include<deque>
#include<ctime>
#include<sstream>
#include<list>
#include<bitset>
using namespace std;
typedef long long ll;
ll ans[233333][23];
ll n,q;
priority_queue<ll,vector<ll>,less<ll> > qqqqq;
struct edge{
	ll nxt,to;
}ed[233333];
ll pnt[233333];
ll head[233333],cnt;ll aaa,bbb;
void addd(ll from,ll to){
	ed[++cnt].to=to;
	ed[cnt].nxt=head[from];
	head[from]=cnt;
	return;
}
void DFS(ll now,ll fa){
	while(qqqqq.size()){
		qqqqq.pop();
	}
	for(ll i=head[now];i;i=ed[i].nxt){
		ll tt=ed[i].to;
		if(tt==fa) continue;
		DFS(tt,now);
	}
	for(ll i=head[now];i;i=ed[i].nxt){
		ll tt=ed[i].to;
		if(tt==fa) continue;
		for(ll j=1;j<=20;++j){
			if(!ans[tt][j]) break;
			qqqqq.push(ans[tt][j]);
		}
	}
	qqqqq.push(pnt[now]);
	for(ll i=1;i<=20;++i){
		if(qqqqq.size()){
			ans[now][i]=qqqqq.top();
			qqqqq.pop();
		}
		else break;
	}
	return;
}
int main(){
	cin>>n>>q;
	for(ll i=1;i<=n;++i){
		cin>>aaa;
		pnt[i]=aaa;
	}
	for(ll i=1;i<n;++i){
		cin>>aaa>>bbb;
		addd(aaa,bbb);
		addd(bbb,aaa);
	}
	DFS(1,0);
	for(ll i=1;i<=q;++i){
		cin>>aaa>>bbb;
		cout<<ans[aaa][bbb]<<endl; 
	}
	return 0;
}

F - Construct Highway

题面

给你一个森林,问能不能加 \(n-m-1\) 条边把它变成每个点的度为 \(d_i\) 的树

思路

无解?

情况很多,但是我们现在只考虑一种,即所有点希望的度数之和不等于 \(2n-2\) (也就是最后的树的边数不是 \(n-1\)

原来没有边?

判无解,直接乱连不就行了?

很遗憾,不行,因为我们在乱连的时候再怎么乱也不会连出环来,但是代码可能,甚至可能是重边、自环。

怎么让它无环呢?

加并查集,再乱连不就行了?

还是不行,因为如果上来就连两个 还需要 的度为 1 的点,这两个点 遂与外人间隔 ,然后就寄了。

所以,我们需要按需要把点分成两类:大于 1 的和等于 1 的。

每次都把等于 1 的点连向大于 1 的点,再更新,然后就好了

正确性?

正确性是显然的,由于每次都从两个集合中各挑一个,所以至少有一个的需求为 1 ,也就是说,加边以后,至少会让一个点与外人间隔,后遂无问津者,所以不会有环;其次,我们只连两个集合之间的,不会出现连完就趋势的情况

这也反映出一个无解情况,即上来就存在与世隔绝的点一定是不行的。

回到这里,那我们这样,再乱连,就行了?

还是不行,我们思考一下,之所以不让他与外人间隔,是因为他还需要与别的点交互,但是在连完最后一条边以后,形成的连通块理应是封闭的。所以最后的最后应该是大于 1 的集合为空,而等于 1 的集合大小 正好为 2 ,否则GG

这样,只需要在这里判一下无解即可。

于是,就好了

再考虑原来有边的情况

我们要把它转化成若干个块块,使得他们两两之间没有边

满足条件的就是 连通块 ,直接并查集

然后,怎么使用呢?

只要将每个连通块中的代表元拎出来,就能将原图转化为原来没边的形式了。

那么,怎么再转换回去呢?

先明确一个东西,对于两个连通块,显然在他们两个中各任意选一个点连起来就行了,也就是说我们可以记录每个代表元拥有哪些边,再直接分配即可。

更简单地,连连通块的时候直接分配下去即可

然后就做完了

代码

//吾日八省吾身:
//输入多而不快读乎?
//题目标注而不freopen乎?
//乘除并列先乘后除乎?
//不手撕样例直接写代码乎?
//不仔细读题直接关页面乎?
//1e9而不开long long乎?
//Ctrl+V而不改名称乎?(papaw->papan IMPLIES tg1=->2=)
//相信评测神机乎?
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<utility>
#include<deque>
#include<ctime>
#include<sstream>
#include<list>
#include<bitset>
using namespace std;
const int MAXN(200233);
stack<int> ndd[MAXN];
queue<int> ones;
queue<int> zzzs;
int fa[MAXN];
int n,m,d[MAXN],a,b,aaaaa,bbbbb;
int ssd[MAXN];
int sumd;
int papaw[MAXN];
int eda[MAXN],edb[MAXN],cnt;
int getfa(int x){
	if(x==fa[x]) return x;
	else return fa[x]=getfa(fa[x]);
}
int R(){
	int x=0,f=1;
	char c='c';
	while(c<'0'||c>'9'){
		f=f*(c=='-'?-1:1);
		c=getchar();
	}
	while(c<='9'&&c>='0'){
		x=(x<<3)+(x<<1)+c-'0';
		c=getchar();
	}
	return x*f;
}
int main(){
	n=R();m=R();
	for(int i=1;i<=n;++i){
		d[i]=R();
		fa[i]=i;
		sumd+=d[i];
	}
	for(int i=1;i<=m;++i){
		a=R();b=R();
		aaaaa=getfa(a);
		bbbbb=getfa(b);
		fa[aaaaa]=bbbbb;
		ssd[a]++,ssd[b]++;
		if(ssd[a]>d[a]||ssd[b]>d[b]){
			cout<<-1<<endl;
			return 0;
		}
	}
	if(sumd!=(n<<1)-2){
		printf("-1\n");
		return 0;
	}
	for(int i=1;i<=n;++i){
		getfa(i);
		papaw[fa[i]]+=(d[i]-ssd[i]);
		for(int j=ssd[i];d[i]-j;++j) ndd[fa[i]].push(i);
	}
	for(int i=1;i<=n;++i){
		if(papaw[i]>1) zzzs.push(i);
		if(papaw[i]==1) ones.push(i);
		if(i==fa[i]&&!papaw[i]){
			cout<<-1<<endl;
			return 0;
		}
	}
	while(!ones.empty()){
		if(zzzs.empty()) break;
		aaaaa=ones.front(),bbbbb=zzzs.front();
		ones.pop();
		if(--papaw[bbbbb]==1){
			zzzs.pop();
			ones.push(bbbbb);
		}
		eda[++cnt]=ndd[aaaaa].top();
		edb[cnt]=ndd[bbbbb].top();
		ndd[aaaaa].pop();ndd[bbbbb].pop();
	}
	if(ones.size()!=2){
		cout<<-1<<endl;
		return 0;
	}
	aaaaa=ones.front();
	ones.pop();
	bbbbb=ones.front();
	eda[++cnt]=ndd[aaaaa].top();
	edb[cnt]=ndd[bbbbb].top();
	for(int i=1;i<=cnt;++i)
		printf("%d %d\n",eda[i],edb[i]);
	return 0;
}

G - Builder Takahashi

题面

思路

代码

Ex - Dice Product 2

题面

思路

代码

posted @ 2022-02-22 22:06  Binaries  阅读(279)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end