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\n",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\n",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 以内的前点,最后记录下方案即可。