20171008 校内模拟赛 题解

L(chess)
【题目描述】
BBS 喜欢和 LGH 下棋,因为这样能增长他的 LG 技巧。今天他们又开始下棋。 BBS 想知
道,以当前的局势,如果双方都以最优策略下棋,那么谁能获得胜利呢?毕竟如果这局会输,
就可以马上用 LFF清理大师清理桌面以保持他的 100%的胜率。
棋盘是一个 8*8 的方格。 BBS 执白,棋子用’W’表示;LGH 执黑,棋子用’B’表示。规则
是这样的:棋盘上为’.’的位置是空格。对于 BBS 来说,如果他有一个棋子在(r,c)的位置且(r-
1,c)的位置为空格,那么他可以将这个棋子移到(r-1,c)的位置,如果他将任意一个棋子移到了
(1,c),那么他将立即获得胜利。对于 LGH 来说,如果他有一个棋子在(r,c)的位置且(r+1,c)的
位置为空格,那么他可以将这个棋子移到(r+1,c)的位置,如果他将任意一个棋子移到了(8,c),
那么他将立即获得胜利。由于 BBS非常的 B,所以总是他先手移动一个棋子,然后交换移动
权。现在给你整个棋盘,请你输出这局的结果。
【输入描述】
输入一个 8*8的棋盘,由’W’,’B’或’.’组成。保证此时第一行没有 W,第八行没有 B。
【输出描述】
如果这盘 BBS能赢,请输出”BBS”;如果这盘 LGH 能赢,请输出”LGH”。
【样例】

........
........
.B....B.
....W...
........
..W.....
........
........

【输出】

BBS
【说明】

本题中,每 10%的数据包括 5 个点,只有通过全部的 5 个点才能获得这 10%的分数。  
【题解】

只需计算下两人的最少获胜步数然后比较即可。

#include<cstdio>
int b[10][10];
int B=8,W=8;
int main(){
    freopen("chess.in","r",stdin);
    freopen("chess.out","w",stdout);
    for(int i=1;i<=8;i++){
        for(int j=1;j<=8;j++){
            char c=getchar();
            while(c!='.'&&c!='B'&&c!='W') c=getchar();
            if(c=='.') b[i][j]=0;
            else if(c=='W') b[i][j]=1;
            else b[i][j]=2;
        }
    }
    for(int i=1;i<=8;i++){
        for(int j=1;j<=8;j++){
            if(b[i][j]==1){
                int ok=1;
                for(int k=1;k<i;k++){
                    if(b[k][j]==2) ok=0;
                }
                if(ok) if(i-1<W) W=i-1;
            }
            if(b[i][j]==2){
                int ok=1;
                for(int k=i+1;k<=8;k++){
                    if(b[k][j]==1) ok=0;
                }
                if(ok) if(8-i<B) B=8-i;
            }
        }
    }
//    printf("%d %d
",B,W);
    if(B<W) puts("LGH");
    else puts("BBS");
    return 0;
}

G(tree)
【题目描述】
BBS 有一个 n 个点的树,现在告诉你这 n-1条边两端的点, 由于他非常 B,所以希望你
能帮他把这棵树放到平面直角坐标系上,并满足以下条件,要不然 BBS 的强迫症会发作:
1. 不 B 不行:每个点的坐标必须为整点,即 x,y 均为整数。同时点的坐标两两不同且
坐标绝对值小于 10^18。
2. 不 B 不行:每条树边都必须平行于 x 轴或 y 轴。
3. 不 S 不行:不能有任意两条树边在非树点处相交。
【输入描述】
第一行为一个整数 n,表示树点的数量。
接下来的 n-1行,每行两个整数 p[i]和 q[i], 表示点 p[i]和点 q[i]有连边。
【输出描述】
第一行输出”YES”或”NO”。 如果能将这棵树放到平面直角坐标系上且满足所以条件, 输
出”YES”, 否则输出”NO”。
如果第一行输出”YES”, 那么接下来的 n 行,每行输出两个整数 x[i],y[i], 表示点 i 的坐标
为(x[i],y[i])。
如果有多种解,允许输出任意一种。
【样例】

7
1 2
1 3
2 4
2 5
3 6
3 7

【输出】

YES
0 0
1 0
0 1
2 0
1 -1
-1 1
0 2

【数据范围】
对于 100%的数据, 1<=n<=30
本题中,每 10%的数据包括 6 个点,只有通过全部的 6 个点才能获得这 10%的分数

【题解】

首先如果有一个点连接了超过 4 条边,那么无法建图。
然后我们可以选取一个点放在原点,然后 DFS 建树。如果当前点和原点直接相连,那么
当前点和原点直接连一条长度为 2^30 的边;如果当前点到原点中间要经过 i 个点,那么当前点
和上一个点连一条长度为 2^(30-i)的边。这样连边可以保证没有两条线相交。

#include<cstdio>
#include<vector>
using namespace std;
int n,X,y;
vector<int> G[31];
long long ax[31],ay[31];
bool vis[31];
int dx[5]={0,-1,1,0};
int dy[5]={-1,0,0,1};
void dfs(int x,int fa,long long dis){
    vis[x]=1;
    int nd=0;
    for(int i=0;i<G[x].size();i++){
        int v=G[x][i];
        if(!vis[v]){
            if(nd==3-fa) nd++;
            ax[v]=ax[x]+dis*dx[nd];
            ay[v]=ay[x]+dis*dy[nd];
            dfs(v,nd,dis/2);
            nd++;
        }
    }
}
int main(){
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        scanf("%d%d",&X,&y);
        G[X].push_back(y);
        G[y].push_back(X);
    }
    for(int i=1;i<=30;i++){
        if(G[i].size()>4){
            puts("NO");return 0;
        }
    }
    ax[1]=ay[1]=0;
    dfs(1,-1,1<<30);
    puts("YES");
    for(int i=1;i<=n;i++){
        printf("%lld %lld
",ax[i],ay[i]);
    }
    return 0;
}

B(journey)
【题目描述】
BBS 作为一名老司机,最喜欢的自然不过开车。今天他新进口了一辆“涡轮喷压”车,
可以在助跑至少 s个单位后在空中飞至多 d 个单位。本来开车是一件很开心的事,从石
头上飞过去也是件很开心的事,可是两件事在一起……怎么会这样呢?瀚嵩现在在 0 的
位置,他要开到 m 的位置,在这段路上有 n 块石头,现在他知道这 n 块石头的位置,
他想请教你要如何开车才能经过这一段路?
【输入描述】
第一行有四个数,分别是 n,m,s,d
第二行为 n 个数,是 n 个石头的位置 w[1],w[2]…w[n]
【输出描述】
输出有若干行,为你开车的过程,每个过程一行,方法有两种:
1、“RUN X”这个表示在地上开 X 个单位长度,不能有两个连续的 RUN命令
2、“JUMP X”这个表示在空中飞 X 个单位长度,这个命令的前一个操作要求要助跑
距离超过 s,飞的长度不超过 d
如果有多种过程能到达终点,允许输出任意一种。
如果不能到达终点,输出“Impossible”
【样例】

3 10 1 3
3 4 7

【输出】

RUN 2

JUMP 3

RUN 1

JUMP 2

RUN 2
【数据范围】

对于 40%的数据, n<=10 并捆绑测试
对于 70%的数据, n<=100000
对于 100%的数据,
1<=n<=200000,2<=m<=10^9,1<=s,d<=10^9,1<=w[i]<=m-1,w[i]<w[i+1]
X 为 1 到 10^9 内的整数

【题解】

将每个障碍的两端视为两个点,分为前点和后点。如果该障碍的前点和上一个障碍的后
点之间的距离不小于 s 且该后点能到达,那么该点可以起跳。 然后将该点作为最新的起跳点
更新后面 d 以内的前点,最后记录下方案即可。

原文地址:https://www.cnblogs.com/nzher/p/7638359.html