2021ICPC网络赛第一场部分题解-The 2021 ICPC Asia Regionals Online Contest (I)

写在前面

本来应该6题的,结果不知道哪个铸币发了H的clar,当即把我们的思路转向三维几何上。当时我们还在想这三维计算几何的正确率有点太高了还在感叹ICPC选手的含金量,直到赛后我才知道这H题的铸币出题人压根不想让我们知道他脑子里在想什么。还好赛时将机位让给了队友写A,不然抄了你吗半天的三维计算几何最后WA那真的是心态炸了。
其他题倒是没啥好说的,就是这H越想越气,有这瞎琢磨的时间去开个B或者C说不定又能++rank。
真的气。不过突然之间看到F。哦,出题人是原*啊,那就说得通了。

A Busiest Computing Nodes

队友写。一开始直接交了发暴力TLE,后来在我想H的时候,用线段树维护下就过了。
这里要提一嘴lexicographic了。由于三个大傻子都没带字典而且英语水平不够,于是直接交了个大小顺序,过了。后来看Clar不明白为啥要特意说不是字典序。
赛后查了下直接笑出声。
不是你但凡提下dict我们也能懂啊。搁这考专八呢。

#include <iostream>
#include <cstdio>
using namespace std;

typedef long long LL;
const LL N=100010;
LL t[N*8],a[N*2];
LL n,k;

LL query(LL l,LL r,LL p,LL x,LL y)
{
	if(x<=l&&r<=y)
		return t[p];
	LL mid=l+r>>1;
	if(y<=mid)
		return query(l,mid,p<<1,x,y);
	if(x>mid)
		return query(mid+1,r,p<<1|1,x,y);
	return min(query(l,mid,p<<1,x,y),query(mid+1,r,p<<1|1,x,y));
}

void modify(LL l,LL r,LL p,LL x,LL y)
{
	if(l==r)
		return void(t[p]=y);
	LL mid=l+r>>1;
	if(x<=mid)
		modify(l,mid,p<<1,x,y);
	if(x>mid)
		modify(mid+1,r,p<<1|1,x,y);
	t[p]=min(t[p<<1],t[p<<1|1]);
}

int main()
{ 	
	scanf("%lld%lld",&k,&n);
	LL res=0;
	for(LL i=0;i<n;++i)
	{
		LL arr,pro;
		scanf("%lld%lld",&arr,&pro);
		LL l=i%k+1,r=i%k+k;
		if(query(1,2*k,1,l,r)>arr)
			continue;
		while(l<r)
		{
			LL mid=l+r>>1;
			if(query(1,2*k,1,l,mid)<=arr)
				r=mid;
			else l=mid+1;
		}
		modify(1,2*k,1,l,arr+pro);
		modify(1,2*k,1,(l+k-1)%(2*k)+1,arr+pro);
		res=max(res,++a[(l-1)%k+1]);
	}
	bool flag=false;
	for(LL i=1;i<=k;++i)
		if(a[i]==res)
			if(flag)
				printf(" %lld",i-1);
			else
			{
				printf("%lld",i-1);
				flag=true;
			}
	return 0;
}

B Convex Polygon

比赛时候没开,回来看了下是裸的二维凸包。虽然学过但是比赛没看到也是没用。但是好像要判断什么输入是否正确我就觉得离谱,算法竞赛还要考察ROBUST的嘛?MARK下,回头补。

D Edge of Taixuan

队友写,图+线段树?

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

typedef long long LL;
const int N=100010;
struct Edge
{
	int l,r,w;
	bool operator < (const Edge &W) const
	{
		return w<W.w;
	}
}e[N];
struct Node
{
	LL idx,pri;
}tr[N*4];
int n,m,t;

void pushdown(int p)
{
	tr[p<<1]=tr[p];
	tr[p<<1|1]=tr[p];
	tr[p]={0,0};
}

void modify(int l,int r,int p,int x,int y,int z,int w)
{
	if(x<=l&&r<=y)
		return void(tr[p]={z,w});
	if(tr[p].idx)
		pushdown(p);
	int mid=l+r>>1;
	if(x<=mid)
		modify(l,mid,p<<1,x,y,z,w);
	if(y>mid)
		modify(mid+1,r,p<<1|1,x,y,z,w);
}

LL query(int l,int r,int p)
{
	//cout<<l<<' '<<r<<' '<<p<<' '<<tr[p].idx<<' '<<tr[p].pri<<endl;
	if(tr[p].idx)
		return (LL)(r-l+1)*tr[p].pri;
	if(l==r)
		return 0;
	int mid=l+r>>1;
	LL res=query(l,mid,p<<1)+query(mid+1,r,p<<1|1);
	return res;
}

bool cmp(Edge &a,Edge &b)
{
	return a.l<b.l;
}

bool judge()
{
	sort(e+1,e+m+1,cmp);
	int l=e[1].l,r=1;
	for(int i=1;i<=n;++i)
	{
		if(e[i].l>r)
			return false;
		r=max(e[i].r,r);
	}
	return e[1].l==1&&r==n;
}

int main()
{
	bool _=false;
	scanf("%d",&t);
	for(int i=1;i<=t;++i)
	{
		memset(tr,0,sizeof tr);
		LL res=0;
		scanf("%d%d",&n,&m);
		for(int j=1;j<=m;++j)
		{
			scanf("%d%d%d",&e[j].l,&e[j].r,&e[j].w);
			res+=(LL)(e[j].r-e[j].l+1)*(e[j].r-e[j].l)/2*e[j].w;
		}
		sort(e+1,e+m+1);
		for(int j=m;j>=1;--j)
			modify(1,n,1,e[j].l+1,e[j].r,e[j].l,e[j].w);
		if(_)
			puts("");
		_=true;
		if(judge())
		{
			res-=query(1,n,1);
			printf("Case #%d: %lld",i,res);
		}
		else
			printf("Case #%d: Gotta prepare a lesson",i);
	}
	return 0;
}

F Land Overseer

看着样例就直接猜中垂线(也就是(a,b-r)这个点,以及它和(2a,0)的连线和第二个圆的交点),于是直接输出2sqrt(aa+(b-r)*(b-r))-r交一发WA。后来就开始用纯数学方法计算距离方程,结果是不管用什么方法都做不出来,最主要的是其他比较合理的猜想都验证不了样例这个数据。最后思路回到原点,发现假如A圆的最低点低于X轴,也就是b<=r的时候,直接沿x轴走到圆B更近,遂加上特判,AC。这题不需要考虑两圆相交,O在圆内之类的情况,因为条件已经将其排除。所以还是相当简单的题目

#include <bits/stdc++.h>
using namespace std;

int main() {
	int t;cin >> t;
	for (int i = 1;i <= t;++i) {
		long long a,b,r;
		cin >> a >> b  >> r;
		cout <<"Case #" << i << ": ";
		if(b > r)
			printf("%.2lf\n",2 * sqrt(a * a + (b-r) * (b - r)) - r);
		else printf("%.2lf\n", (double)(2*a - r));
	}
	return 0;
}

H Mesh Analysis

在给Clar之前,读完题我说:这neighboring不会是和它一起构成这个图形的点吧。看了Clar,哦,原来要考虑在三角形内部的点啊,还是三维,挺难的。遂开始抄板子......
用set保存每个点相连的点以及属于的图形即可(因为会重复),最好用unordered_map映射下,谁知道id范围是多少呢。
对,这题2~n+1行的输入完全没用。服了。
输出要稍微考虑下,注意最后不能空行,空集输出[],也不是很难。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

unordered_map<ll,set<ll> > belongel;
unordered_map<ll,set<ll> > belongpo;


int main() {
	int n,m;
	cin >> n >> m;
	for (int i = 0;i < n;++i) {
		ll id;
		double x,y,z;
		cin >> id >> x >> y >> z;
	}

	for (int i = 0;i < m;++i) {
		ll id,idx;
		cin >> id >> idx;
		if (idx == 102) {
			ll x,y;
			cin >> x >> y;
			belongpo[x].insert(y);
			belongpo[y].insert(x);
			belongel[x].insert(id);
			belongel[y].insert(id);
		}else{
			ll x,y,z;
			cin >> x >> y >> z;
			belongpo[x].insert(y);
			belongpo[x].insert(z);
			belongpo[y].insert(x);
			belongpo[y].insert(z);
			belongpo[z].insert(x);
			belongpo[z].insert(y);

			belongel[x].insert(id);
			belongel[y].insert(id);
			belongel[z].insert(id);
		}
	}

	int L;cin >> L;
	bool fir = 1;
	while (L--) {
		if (fir){
			fir = false;
		}else{
			cout << endl;
		}

		ll id ;cin >> id;
		cout << id << endl;
		bool _ = true;
		//point
		set<ll> &outt = belongpo[id];
		if (outt.empty()){
			cout <<"[]\n";
			_ = false;
		}
		if (_){
			cout << '[';
			for (auto it : outt) {
				if (it != *outt.begin())	cout << ',';
				cout << it;
			}
			cout << "]\n";
		}

		_ = true;

		set<ll> &oute = belongel[id];
		if (oute.empty()) {
			cout << "[]";
			_ = false;
		}

		if (_){
			cout << '[';
			for (auto it : oute) {
				if (it != *oute.begin())	cout << ',';
				cout << it;
			}
			cout << ']';
		}
	}
	return 0;
}

第一个A的题目。题意:在数轴上找到被A为圆心,R为半径包围且属于集合S的元素(除它自己)。这题关键是输入,我们想了个办法,先while(cin >> x)读到eof,并且记录个数n,然后最后两个数拎出来为A和R,最后排序前n-2个元素找就行了。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
long long tmp[maxn];
long long a[maxn];
int main() {
	int n = 0;
	long long x;
	while (cin >> x) {
		tmp[n++] = x;
	}

	n = n - 3;
	sort(tmp,tmp+n+1);
	long long A = tmp[n + 1];
	long long r = tmp[n + 2];
	//cout << A << ' ' << r << endl;
	bool f = false;

	for (int i = n;i >= 0;--i) {
		if (tmp[i] <= A + r && tmp[i] >= A - r) {
			cout << tmp[i] << ' ';
			f = true;
		}
	}

	if(!f) cout << '\n';
 
	return 0;
}

K Segment Routing

队友写,应该是图的遍历(?),反正是模拟。题目太长压根没看,(其实是没学过计网)

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

const int N=100010,M=2000010;
int t,n,m,h[N],e[M],d[N],r[N];

int main()
{
	scanf("%d",&t);
	bool _=false;
	for(int i=1;i<=t;++i)
	{
		if(_) puts("");
		_=true;
		printf("Case #%d: ",i);
		scanf("%d%d",&n,&m);
		for(int j=1;j<=n;++j)
		{
			scanf("%d",&d[j]);
			h[j]=h[j-1]+d[j-1];
			for(int k=1;k<=d[j];++k)
				scanf("%d",&e[h[j]+k-1]);
		}
		for(int j=1;j<=m;++j)
		{
			int s,l;
			scanf("%d%d",&s,&l);
			for(int k=1;k<=l;++k)
				scanf("%d",&r[k]);
			bool flag=true;
			for(int k=1;k<=l&&flag;++k)
			{
				if(r[k]>d[s])
					flag=false;
				s=e[h[s]+r[k]-1];
				if(s>n)
					flag=false;
			}
			puts("");
			if(flag)
				printf("%d",s);
			else
				printf("Packet Loss");
		}
	}
	return 0;
}

总结

下场总不是华为出题了吧。XCPC今年太梦幻了。

posted @ 2021-09-20 14:22  AlexanderZ.Tang  阅读(762)  评论(0编辑  收藏  举报