Codeforces Round #203 (Div. 2) 题解
A.TL
题意:有n(100)个数的序列a,以及m(100)个序列b,问max(mina*2,maxa)是否小于minb
思路:直接查找即可
代码:
#include <bits/stdc++.h> using namespace std; int a[105],b[105]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=m;i++)scanf("%d",&b[i]); sort(a+1,a+1+n); sort(b+1,b+1+m); int ans=max(a[1]*2,a[n]); if(ans>=b[1])puts("-1"); else printf("%d\n",ans); return 0; }
B.Resort
题意:给你一张n(1e5)个点的图,点有两种类型,一种是起点,一种是终点,问你从任意起点开始,打印到达终点的最长路,路径满足除终点外其他的点都是起点,从起点到终点不能有岔路,路径是唯一的,路径上的点出度为1
思路:反向建图,然后从每个终点开始搜索,维护最长路径的起点和终点,最后在搜索出路径,打印即可
代码:
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+7; int n; vector<int>mp[maxn]; bool vis[maxn]; int anss,anst,ansl; int in[maxn]; int stk[maxn],top; void dfs(int s,int x,int num) { for(int i=0;i<mp[x].size();i++){ int v=mp[x][i]; if(vis[v])continue; if(in[v]<=1){ if(num+1>ansl){ anss=s;anst=v;ansl=num+1; } dfs(s,v,num+1); } } } void dfs(int x,int t) { stk[++top]=x; if(x==t)return ; for(int i=0;i<mp[x].size();i++){ dfs(mp[x][i],t); } } int main() { top=0; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&vis[i]); if(vis[i])anss=i,anst=i,ansl=1; } for(int i=1;i<=n;i++){ int x; scanf("%d",&x); if(!x)continue; mp[i].push_back(x); in[x]++; } for(int i=1;i<=n;i++){ if(!vis[i])continue; dfs(i,i,1); } dfs(anss,anst); printf("%d\n",top); for(int i=top;i>=1;i--){ printf("%d ",stk[i]); } puts(""); return 0; }
C.Bombs
题意:平面上有n(1e5)个炸弹,有一个机器人在(0,0)点,机器人有3中操作
1 x dir 表示机器人向dir(UDLR)方向走了x格,
2 表示机器人捡起炸弹
3 表示机器人摧毁炸弹
机器人智能在(0.0)处摧毁炸弹,问你机器人最少需要多少步可以清除所有的炸弹,机器人身上只能带一个炸弹,没有炸弹在两个相同的点,以及炸弹不会再(0,0)点
思路:对炸弹到原点的距离进行排序,然后直接打印指令。
代码:
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+7; struct point { int x,y; bool operator <(const point &b)const { return abs(x)+abs(y)<abs(b.x)+abs(b.y); } }a[maxn]; int n; int main() { scanf("%d",&n); int ans=0; for(int i=1;i<=n;i++){ scanf("%d%d",&a[i].x,&a[i].y); if(a[i].x!=0)ans++; if(a[i].y!=0)ans++; } sort(a+1,a+1+n); ans*=2;ans+=n*2; printf("%d\n",ans); for(int i=1;i<=n;i++){ if(a[i].y > 0) printf("1 %d U\n", abs(a[i].y)); if(a[i].y < 0) printf("1 %d D\n", abs(a[i].y)); if(a[i].x > 0) printf("1 %d R\n", abs(a[i].x)); if(a[i].x < 0) printf("1 %d L\n", abs(a[i].x)); printf("2\n"); if(a[i].y > 0) printf("1 %d D\n", abs(a[i].y)); if(a[i].y < 0) printf("1 %d U\n", abs(a[i].y)); if(a[i].x > 0) printf("1 %d L\n", abs(a[i].x)); if(a[i].x < 0) printf("1 %d R\n", abs(a[i].x)); printf("3\n"); } return 0; }
D.Looking for Owls
题意:平面上有3e5条线段,以及1000个圆,满足下面四个条件就称做猫头鹰,问平面上有多少个猫头鹰
- 圆ij相对于线段k对称
- 圆ij不想交
- 圆ij有相同的半径
- 线段k和圆ij圆心连线相交
思路:因为圆的范围小,所以n2枚举圆,然后判断线段,把每条线段都按照斜率和截距进行标记,相同的存在一个vector中,对于同一个vector中的线段在按照差分的方法标记有多少线段覆盖了圆ij圆心的中点,最后统计答案即可
代码:
#include <bits/stdc++.h> using namespace std; typedef pair<int,pair<int,int> >piii; struct point { int x,y; void input() { scanf("%d%d",&x,&y); } point(int x=0,int y=0):x(x),y(y){} int len() { return x*x+y*y; } point operator +(const point &b)const { return point(x+b.x,y+b.y); } point operator *(const int v)const { return point(v*x,v*y); } point operator -(const point &b)const { return point(x-b.x,y-b.y); } point operator /(const int v)const { return point(x/v,y/v); } }; #define sqr(x) ((x)*(x)) int dis(point a,point b) { return (a-b).len(); } piii getpiii(point a,point b) { int dx=a.x-b.x,dy=a.y-b.y; if(dy==0)return make_pair(a.y,make_pair(0,0)); if(dx==0)return make_pair(a.x,make_pair(0,1)); if(dx<0){ dx*=-1,dy*=-1; } int d=__gcd(abs(dx),abs(dy)); dx/=d;dy/=d; int res=(a.y%dy+dy)%dy; res=a.x+(res-a.y)/dy*dx; return make_pair(res,make_pair(dx,dy)); } piii mipiii(point a,point b) { point mid=(a+b)/2,ve=a-b; swap(ve.x,ve.y);ve.x*=-1; return getpiii(mid+ve,mid-ve); } map<piii,vector<pair<int,int> > > mp; map<piii,vector<int> >ans; int getans(piii s,int v) { if(mp.find(s)==mp.end())return 0; vector<pair<int,int> >&use=mp[s]; int pos=upper_bound(use.begin(),use.end(),make_pair(v,1))-use.begin(); return ans[s][pos]; } const int maxn=2500; point cir[maxn]; int r[maxn]; int main() { int n,m; scanf("%d%d",&n,&m); point a,b; for(int i=1;i<=n;i++){ a.input();b.input(); a=a*2;b=b*2; if(a.x != b.x){ mp[getpiii(a,b)].push_back(make_pair(min(a.x,b.x),1)); mp[getpiii(a,b)].push_back(make_pair(max(a.x,b.x)+1,-1)); } else{ mp[getpiii(a,b)].push_back(make_pair(min(a.y,b.y),1)); mp[getpiii(a,b)].push_back(make_pair(max(a.y,b.y)+1,-1)); } } for(auto &it:mp){ sort(it.second.begin(),it.second.end()); vector<int> &res=ans[it.first]; int pre=0; res.push_back(pre); for(auto j:it.second){ pre+=j.second; res.push_back(pre); } } for(int i=0;i<m;i++){ cir[i].input(); scanf("%d",&r[i]); cir[i]=cir[i]*2; r[i]*=2; } int res=0; for(int i=0;i<m;i++){ for(int j=i+1;j<m;j++){ if(r[i]==r[j]&&dis(cir[i],cir[j])>sqr(r[i]+r[j])){ int mid; if(cir[i].y==cir[j].y)mid=cir[i].y; else mid=(cir[i].x+cir[j].x)/2; res+=getans(mipiii(cir[i],cir[j]),mid); } } } printf("%d\n",res); return 0; }
E.Wrong Floyd
题意:给你n个点和m条边,以及一个点集k,构造出下面代码答案错误的一张图
思路:因为有的点没有遍历到,所以肯定有的地方没有达到最小值,找到一个没有在点集中的点,如果找不到肯定是全部覆盖到了,找到这个点后,在点集k中随便选一个点,把点集中的点记为s,点集外的点记为e,先把se中间连一条边,然后把其他的点尽可能的建边达到完全图,但不和e点,此时的建图都是可是让代码产生错误的,点e没有被松弛到,如果还有余边就把不等于se并且不再点集k中的点建边,这些边依然不会贡献答案如果还有边,那么代表最后的答案肯定都会被松弛,打印-1,如果没有剩余的边,就直接打印构造即可
代码:
#include <bits/stdc++.h> using namespace std; const int maxn=305; bool vis[maxn]; vector<pair<int,int> >ans; int n,m,k; bool check() { int s=0,e=0; for(int i=1;i<=n;i++){ if(!vis[i]){ s=i;break; } } if(s==0)return false; for(int i=1;i<=n;i++){ if(vis[i]){ e=i;break; } } ans.push_back(make_pair(s,e)); m--; for(int i=1;i<=n;i++){ if(i==e)continue; for(int j=i+1;j<=n;j++){ if(j==e)continue; if(m>0)ans.push_back(make_pair(i,j)),m--; } } for(int i=1;i<=n;i++){ if(i==s||i==e)continue; if(m>0&&!vis[i])ans.push_back(make_pair(i,e)),m--; } return m==0; } int main() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=k;i++){ int x; scanf("%d",&x); vis[x]=true; } if(!check()){ puts("-1"); } else{ for(int i=0;i<ans.size();i++){ printf("%d %d\n",ans[i].first,ans[i].second); } } return 0; }