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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

D.Looking for Owls

题意:平面上有3e5条线段,以及1000个圆,满足下面四个条件就称做猫头鹰,问平面上有多少个猫头鹰

  1. 圆ij相对于线段k对称
  2. 圆ij不想交
  3. 圆ij有相同的半径
  4. 线段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;
}
View Code

 

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;
}
View Code

 

 

 

posted @ 2019-02-17 17:10  啦啦啦天啦噜  阅读(176)  评论(0编辑  收藏  举报