2021年度训练联盟热身训练赛第一场
ICPC North Central NA Contest 2019
比赛题目:
这学期的周赛都将以训练联盟组织的牛客网上的比赛来进行。这是本学期的第一场比赛,也是我第一次参加五个小时的ICPC模拟赛,过了6道题,表现就目前而言算比较满意了,但赛后看了其他题目别人AC的代码,自己还是有很大提升空间的。继续努力!
以下是我通过题目的AC代码:
A题 Weird Flecks, But OK
最小覆盖圆的模板题,也差不多是第一次做计算几何题,照着模板敲就可以通过了。
#include <bits/stdc++.h>
#define eps 1e-10
using namespace std;
const int maxn=5005;
int sgn(double x)
{
if(fabs(x)<eps)
return 0;
else
return x<0?-1:1;
}
struct Point
{
double x,y;
}Z[maxn],X[maxn],Y[maxn];
double Distance(Point a,Point b)
{
return hypot(a.x-b.x,a.y-b.y);
}
Point circle_center(const Point a,const Point b,const Point c)//求三角形abc的外接圆的圆心
{
Point center;
double a1=b.x-a.x,b1=b.y-a.y,c1=(a1*a1+b1*b1)/2;
double a2=c.x-a.x,b2=c.y-a.y,c2=(a2*a2+b2*b2)/2;
double d=a1*b2-a2*b1;
center.x=a.x+(c1*b2-c2*b1)/d;
center.y=a.y+(a1*c2-a2*c1)/d;
return center;
}
void min_cover_circle(Point *p,int n,Point &c,double &r)//求最小覆盖圆,返回圆心c、半径r
{
random_shuffle(p,p+n);
c=p[0],r=0;
for(int i=1;i<n;i++)
{
if(sgn(Distance(p[i],c)-r)>0)
{
c=p[i],r=0;
for(int j=0;j<i;j++)
{
if(sgn(Distance(p[j],c)-r)>0)
{
c.x=(p[i].x+p[j].x)/2;
c.y=(p[i].y+p[j].y)/2;
r=Distance(p[j],c);
for(int k=0;k<j;k++)
{
if(sgn(Distance(p[k],c)-r)>0)
{
c=circle_center(p[i],p[j],p[k]);
r=Distance(p[i],c);
}
}
}
}
}
}
}
int main()
{
int n;
scanf("%d",&n);
double a,b,c,ans1,ans2,ans3;
Point p1,p2,p3;
for(int i=0;i<n;i++)
{
scanf("%lf%lf%lf",&a,&b,&c);
Z[i].x=a,Z[i].y=b;
X[i].x=b,X[i].y=c;
Y[i].x=a,Y[i].y=c;
}
min_cover_circle(Z,n,p1,ans1);
min_cover_circle(X,n,p2,ans2);
min_cover_circle(Y,n,p3,ans3);
ans1*=2,ans2*=2,ans3*=2;
if(ans1<ans2)
ans2=ans1;
if(ans2<ans3)
ans3=ans2;
printf("%.10f\n",ans3);
return 0;
}
D题 Some Sum
这道题算是签到题,开场几分钟就有很多人通过了,简单思考即可得出结论。
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int n;
cin>>n;
if(n%2==1)
cout<<"Either"<<endl;
else
{
if((n/2)%2==1)
cout<<"Odd"<<endl;
if((n/2)%2==0)
cout<<"Even"<<endl;
}
return 0;
}
E题 Early Orders
一道单调栈的题目。上学期周赛做过一道类似的,这道题需要注意栈顶的数字在后面还是否存在,如果不存在就不能弹出了。
#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;
int n,k,a[200005],cnt[200005],vis[200005],ans[100005];
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>k;
for(int i=0;i<n;i++)
{
cin>>a[i];
cnt[a[i]]++;
}
stack<int> s;
for(int i=0;i<n;i++)
{
cnt[a[i]]--;
if(vis[a[i]])
continue;
while(!s.empty()&&a[i]<s.top()&&cnt[s.top()]>0)
{
vis[s.top()]=0;
s.pop();
}
s.push(a[i]);
vis[a[i]]=1;
}
for(int i=k;i>=1;i--)
{
ans[i]=s.top();
s.pop();
}
for(int i=1;i<=k;i++)
cout<<ans[i]<<" ";
cout<<endl;
return 0;
}
F题 Pulling Their Weight
数组查找问题,也比较简单。这道题数据范围不大,直接遍历也能通过。使用前缀和处理、lower_bound二分可以提高效率。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,tot=0,a[100005],sum[100005],cnt[20005];
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
cnt[a[i]]++;
tot+=a[i];
}
sort(a,a+n);
sum[0]=a[0];
for(int i=1;i<n;i++)
sum[i]=sum[i-1]+a[i];//前缀和
int ans;
for(int t=1;t<=20000;t++)
{
int pos=lower_bound(a,a+n,t)-a;
if(sum[pos-1]==tot-sum[pos-1]-cnt[t]*t)
{
ans=t;
break;
}
}
cout<<ans<<endl;
return 0;
}
H题 On Average They’re Purple
很容易发现结论,答案就是最短路径长度减1。经典的图论BFS问题。数据范围较大,用DFS会超时。用链式前向星存图,注意因为是无向图,存边的数组大小要开两倍,比赛时候段错误(数组越界)WA了一发。
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
const int num=200005;
struct edge
{
int to,next;
}edge[num];
int cnt,head[num];
void init()
{
for(int i=0;i<num;i++)
{
edge[i].next=-1;
head[i]=-1;
}
cnt=0;
}
void addedge(int u,int v)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
int n,m,dis[num],vis[num];
void bfs(int x)
{
queue<int> q;
q.push(x);
vis[x]=1;
while(!q.empty()&&!vis[n])
{
int t=q.front();
q.pop();
for(int i=head[t];i!=-1;i=edge[i].next)
if(!vis[edge[i].to])
{
q.push(edge[i].to);
vis[edge[i].to]=1;
dis[edge[i].to]=dis[t]+1;
}
}
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
init();
cin>>n>>m;
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
addedge(a,b);
addedge(b,a);
}
bfs(1);
cout<<dis[n]-1<<endl;
return 0;
}
J题 This Ain’t Your Grandpa’s Checkerboard
简单的棋盘遍历问题,也是一道签到题,没有技术含量,注意细节即可。
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n,flag=1;
char a[25][25];
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>a[i][j];
for(int i=0;i<n;i++)
{
int wcnt=0,bcnt=0,lx=1;
if(a[i][0]=='W') wcnt++;
if(a[i][0]=='B') bcnt++;
for(int j=1;j<n;j++)
{
if(a[i][j]==a[i][j-1])
lx++;
else
lx=1;
if(lx>=3)
{
flag=0;
goto label;
}
if(a[i][j]=='W') wcnt++;
if(a[i][j]=='B') bcnt++;
}
if(wcnt!=bcnt)
{
flag=0;
goto label;
}
}
for(int j=0;j<n;j++)
{
int wcnt=0,bcnt=0,lx=1;
if(a[0][j]=='W') wcnt++;
if(a[0][j]=='B') bcnt++;
for(int i=1;i<n;i++)
{
if(a[i][j]==a[i-1][j])
lx++;
else
lx=1;
if(lx>=3)
{
flag=0;
goto label;
}
if(a[i][j]=='W') wcnt++;
if(a[i][j]=='B') bcnt++;
}
if(wcnt!=bcnt)
{
flag=0;
goto label;
}
}
label:
if(flag==1)
cout<<"1"<<endl;
else
cout<<"0"<<endl;
return 0;
}