XJOI模拟训练22

A.扫雷(minesweeper)

题目描述 :

你需要编写一个扫雷交互器,获取地图信息,依次读入玩家操作并返 回对应结果。
扫雷的局面是一个 n × m 的矩形,其中一些位置为地雷而另一些位置 为空地,扫雷局面将以字符矩阵的形式输入。将第 i 行第 j 列的位置记作 ?i, j?。特别地,令 k 为地雷的数量,保证有 0 < k < n × m。
一开始玩家无法得知除了 n, m, k 之外的扫雷局面的任何信息。
你需要维护名为玩家地图的字符矩阵,初始时矩阵中所有元素为 _(下划线)。

玩家将进行 q 次操作,每次将选取一个位置 \(?x, y?\),并用以下三种 方式之一点击(若游戏结束,你应该忽略游戏结束后的所有玩家操作,即判 定这些操作为无效操作,反之即为有效操作):

  1. 左键点击: 若 \(?x, y?\) 已经被打开或玩家地图中这个位置为 P(P 表示旗子),则不 进行任何操作;否则若 \(?x, y?\) 为地雷,则游戏失败;否则对 \(?x, y?\) 进 行打开操作。
  2. 右键点击: 若 \(?x, y?\) 已经被打开,则不进行任何操作;否则 若玩家地图中位置 \(?x, y?\) 为 **_**(下划线),将其改为 P, 若玩家地图中位置 \(?x, y?\) 为 P,将其改为 ?, 若玩家地图中位置 \(?x, y?\) 为 ?,将其改为 _。
  3. 中键点击: 若 \(?x, y?\) 未被打开,或玩家地图中这个位置周围相邻的 8 个位置的 P 的个数不等于玩家地图中该位置的数值,则不进行任何操作;否则对 于 \(?x, y?\) 周围相邻 8 个未被打开且在玩家地图中不是 P 的位置,如果 存在至少一个位置是地雷,则游戏失败;否则对这些位置进行打开操 作。

打开操作: 对位置 \(?x, y?\) 进行的打开操作按照如下方式进行:

  1. 将 \(?x, y?\) 标记为被打开。
  2. 在玩家地图中位置 \(?x, y?\) 改为 c(0 ≤ c ≤ 8),表示这个位置周围相邻 的 8 个位置的地雷数量。
  3. 如果 c = 0,则对其周围相邻的 8 个未被打开且在玩家地图中不是 P 的位置进行打开操作。
  4. 这个操作是递归进行的,直到所有子操作都结束后,本次打开操作才 算结束。

游戏结束,游戏结束有以下三种情况:

  1. 游戏失败:即上述规则中的情况,试图对为地雷的位置进行打开操作 就会导致游戏失败。
  2. 游戏胜利:若某一次操作结束后,未被打开的位置个数恰好为 k,则 此次操作后游戏胜利。
  3. 退出游戏:若玩家操作结束,但上述两种情况均未出现,则视作玩家 退出游戏。

在每一次操作后,你需要返回结果,具体规则如下:

  • 若此次操作为无效操作,返回 INVALID;否则
  • 若此次操作后游戏失败,返回 LOSE;否则
  • 先返回 RUNNING:,然后在同一行返回用中括号包含的,玩家地图中 有更改的位置以及更改后的值,格式为 <x, y, val> ;更改的位置 按照 x 坐标为第一关键字从小到大,y 坐标为第二关键字从小到大 的顺序排序,相邻两个更改的位置用 , 隔开。例如某一次操作后可能 返回:RUNNING: [];或 RUNNING: [<3, 3, ?>]。注意其中空格的位置。
  • 若此次操作后游戏胜利,再在新的一行返回 WIN。
  • 若此次操作后退出游戏,再在新的一行返回 QUIT。

输入格式 :

输入文件包含多组数据。
第一行一个正整数 T 表示数据组数,接下来每 n + q + 2 行(意义见 下)表示一组数据。
每组数据第一行两个正整数 n, m 分别表示扫雷局面的高度和宽度。
每组数据接下来 n 行,第 i 行一个长度为 m 的字符串,仅包含 _ 和 \(*\) 两种字符。
如果第 j 个字符为 *,则表示第 i 行第 j 列为地雷,否则为空 地。
每组数据接下来若干行,每行三个正整数 op, x, y 表示玩家的一次操作, 具体操作见题目描述。
每组数据最后一行一个数 0,表示玩家操作结束。令玩家操作次数为 q。

输出格式 :

对于每组数据,输出若干行,每行表示一次操作的返回结果,若在某一 次操作后游戏结束,请输出对应的结果。
相邻的两组数据之间使用一行 \(==========\)(10 个 = 字符,不包含引 号)隔开。

数据范围 :

对于所有测试点:1 ≤ T ≤ 30,3 ≤ n, m ≤ 200,0 ≤ q ≤ 10000, op ∈ {1, 2, 3},1 ≤ x ≤ n,1 ≤ y ≤ m;

Solution :

很少做的一道模拟好题,
题目各种情况其实已经描述得很清楚了,按题意大力模拟就好了。
对无效操作的定义没有看清楚导致爆零 =w=

Code :

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define fr(i, a, b) for(int (i) = (a); (i) <= (b); (i)++)
typedef pair<int, int> pii;
typedef pair<pii, int> pli;
const int N = 205;
int n, m, T, close;
char s[N][N], a[N][N];
vector<pli> prt;
template <class T> void read(T &x) {
    bool f = false; x = 0;
    char ch = getchar();
    while (ch<'0' || ch>'9') {if (ch == '-') f = true; ch = getchar();}
    while (ch>='0' && ch<='9') x = x * 10 + ch - '0', ch = getchar();
    if (f) x = -x;
}
inline void open(int x, int y) {
    close --;
    int cnt = 0;
    fr(i, x - 1, x + 1) fr(j, y - 1, y + 1) {
        if (i < 1 || i > n || j < 1 || j > m) continue;
        if (a[i][j] == '*') cnt++;
    }
    prt.pb(mp(mp(x, y), cnt));
    s[x][y] = '0' + cnt;
    if (cnt == 0) {
        fr(i, x - 1, x + 1) fr(j, y - 1, y + 1) {
            if (i < 1 || i > n || j < 1 || j > m) continue;
            if (s[i][j] == '_' || s[i][j] == '?') {
                open(i, j);
            }
        }
    }
}
inline void shuchu() {
    sort(prt.begin(), prt.end());
    int sz = prt.size() - 1;
    printf("RUNNING: [");
    fr(i, 0, sz) {
        printf("<%d, %d, %d>", prt[i].fi.fi, prt[i].fi.se, prt[i].se);
        if (i != sz) printf(", ");
    }
    puts("]");
}
int main() {
    read(T);
    while (T--) {
        read(n), read(m);
        int mine = 0;
        fr(i, 1, n) {
            scanf("%s", a[i] + 1);
            fr(j, 1, m) if (a[i][j] == '*') mine++;
        }
        fr(i, 1, n) fr(j, 1, m) s[i][j] = '_';
        int op, x, y; close = n * m;
        bool lose = false, win = false;
        while (~scanf("%d", &op)) {
            if (op == 0) {
                if (!win && !lose) puts("QUIT");
                break;
            }
            read(x), read(y);
            if (lose || win) {puts("INVALID"); continue;}
            if (op == 1) {
                if (s[x][y] >= '0' && s[x][y] <= '9' || s[x][y] == 'P')  {puts("RUNNING: []"); continue;}
                if (a[x][y] == '*') {
                    puts("LOSE"); lose = true;
                    continue;
                }
                prt.clear();
                open(x, y); shuchu();
                if (close == mine) {puts("WIN"); win = true; continue;}
            }
            if (op == 2) {
                if (s[x][y] >= '0' && s[x][y] <= '9')  {puts("RUNNING: []"); continue;}
                if (s[x][y] == '_') s[x][y] = 'P';
                else if (s[x][y] == 'P') s[x][y] = '?';
                     else s[x][y] = '_';
                printf("RUNNING: [<%d, %d, %c>]\n", x, y, s[x][y]);
            }
            if (op == 3) {
                if (!(s[x][y] >= '0' && s[x][y] <= '9')) {puts("RUNNING: []"); continue;}
                int cnt = 0;
                fr(i, x - 1, x + 1) fr(j, y - 1, y + 1) {
                    if (i < 1 || i > n || j < 1 || j > m) continue;
                    if (s[i][j] == 'P') cnt++;
                }
                if (cnt != (s[x][y] - '0')) {puts("RUNNING: []"); continue;}
                prt.clear();
                fr(i, x - 1, x + 1) {
                    fr(j, y - 1, y + 1) {
                        if (i < 1 || i > n || j < 1 || j > m) continue;
                        if (s[i][j] == 'P' || (s[i][j] >= '0' && s[i][j] <= '9')) continue;
                        if (a[i][j] == '*') {
                            lose = true;
                        } else open(i, j);
                    }
                }
                if (lose) {puts("LOSE"); continue;}
                shuchu();
                if (close == mine) {puts("WIN"); win = true; continue;}
            }
        }
        if (T) puts("==========");
    }
    return 0;
}

B.五彩树 (Colorful)

题目描述 :

给定一棵 \(n\) 个节点的树,节点编号为 \(1 ~ n\)。 每个节点都染上了一种颜色,总共有 \(m\) 种不同的颜色,编号为 \(1 ~ m\)。 记节点 \(i\) 的颜色为 \(c_i\)。 小 X 喜欢颜色,他想要选出这棵树的一个连通的部分 \(S\),并且 \(S\) 中的 节点必须包含至少 \(k\) 种不同的颜色。即 \(S\) 必须满足其是原树的一个连通的 导出子图,并且集合 \({c_u | u ∈ S}\) 的大小至少为 \(k\)。 但是小 Y 讨厌颜色,她让小 X 把除了 \(S\) 中的节点之外的所有节点的 颜色都擦除,并且呆在一个节点 \(u\),她想要最大化节点 \(u\) 与任意的有颜色 的节点之间的距离的最小值。即最大化 \(min \{dis(u, x)\} x ∈ S\),\(dis(x, y)\) 表示节点 \(x\) 与节点 \(y\) 之间的距离,这里距离定义为最少经过的边数。 小 X 还没有确定选择 \(S\) 的方案,他求助于你,你需要满足上述所有条 件,并且最大化 \(u\) 与 \(S\) 中的节点的距离。

输入格式 :

第一行三个正整数 \(n, m, k\),意义见题目描述。
第二行 \(n\) 个正整数 \(c1...n\) 依次表示每个节点的颜色。
接下来 \(n ? 1\) 行,每行两个正整数 \(x, y\) 表示一条连接节点 \(x\) 与节点 \(y\) 的边。

输出格式 :

输出一行一个数表示最大距离。

样例 :

输入

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

输出

3

数据范围 :

对于所有数据,\(1 ≤ k ≤ m ≤ n ≤ 10^6\),\(1 ≤ ci ≤ m\)。

Solution :

该树是一棵无根树,我们钦定 1号点 为根结点,贪心的想,最后选出来的子图 \(S\) 有两种情况

  1. 是以 1 为根的树的子树
  2. 是以 1 为根的树删去一个子树

对于第一种情况,dis的最小值可以dp求出来
对于第二种情况,直接dfs找最大深度即可
这样我们能求出对于一个点作为 子树的根 的两种情况分别得到的dis值
接下来统计以 某一点为根的子树 内的和不包含这个子树的 颜色种类
考虑以某一点为根的子树dfs序是连续的,将dfs复制一份接在后面,则删去某一点为根的子树后剩下的部分在dfs序中也是连续的,于是我们就可以直接在dfs序上用双指针处理出每一点 达到 k 种颜色最早的位置,判断该位置是否包含在该点子树内即可。

dfs序真是个好东西 =w=

Code :

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 7, inf = 1e9 + 7;
int n, m, k, cnt = 0, inx = 0;
int c[N], ct[N], num[N * 2], in[N], out[N];
int fir[N], nxt[N * 2], to[N * 2], dis[N], Mx[N], pos[N * 2];
inline void AddEdge(int u, int v) {
    nxt[++cnt] = fir[u];
    fir[u] = cnt, to[cnt] = v;
}
void dfs1(int u, int fa) {
    in[u] = ++inx;
    num[inx] = u;
    for (int i = fir[u]; i; i = nxt[i]) {
        int v = to[i];
        if (v == fa) continue;
        dfs1(v, u);
        dis[u] = max(dis[u], dis[v] + 1);
    }
    out[u] = inx;
}
void dfs2(int u, int fa) {
    int mx = 0, cmx = 0;
    for (int i = fir[u]; i; i = nxt[i]) {
        int v = to[i];
        if (v == fa) continue;
        if (dis[v] + 1 >= mx) cmx = mx, mx = dis[v] + 1;
        else cmx = max(cmx, dis[v] + 1);
    }
    for (int i = fir[u]; i; i = nxt[i]) {
        int v = to[i];
        if (v == fa) continue;
        Mx[v] = max(Mx[u] + 1, (dis[v] + 1 == mx) ? cmx + 1 : mx + 1);
        dfs2(v, u);
    }
}
int main() {
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= n; i++) scanf("%d", &c[i]);
    for (int i = 1; i < n; i++) {
        int x, y;
        scanf("%d%d", &x, &y);
        AddEdge(x, y);
        AddEdge(y, x);
    }
    dfs1(1, 0);
    dfs2(1, 0);
    for (int i = 1; i <= n; i++) num[i + n] = num[i];
    int nw = 0;
    for (int i = 1, j = 1; j <= 2 * n; j++) {
        if (ct[c[num[j]]] == 0) nw ++;
        ct[c[num[j]]] ++;
        while (nw > k || ct[c[num[i]]] > 1) {
            ct[c[num[i]]] --;
            if (ct[c[num[i]]] == 0) nw --;
            i ++;
        }
        if (nw >= k) pos[j] = i;
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (pos[out[i]] >= in[i]) ans = max(ans, Mx[i]);
        if (pos[in[i] + n - 1] > out[i]) ans = max(ans, dis[i] + 1);
    }
    printf("%d\n", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/bryane/p/11758100.html

时间: 2024-08-30 08:56:16

XJOI模拟训练22的相关文章

XJOI模拟训练11 - B.Rcomb

B.Rcomb 题目描述 : Na老师有\(N\)张卷子排成一列,第i张卷子有其难度\(V_i\),由于X爷的出现,Na老师需要将这些卷子合并为1张.每次Na老师以相等的概率随机选择两张相邻卷子,消耗两张卷子难度和的体力,得到一张难度为两张卷子难度和的卷子,求 Na老师需要消耗的体力期望值. 输入格式 : 第一行:一个整数\(N\). 第二行:\(N\)个整数\(V_1.V_2.....V_N\). 输出格式 : 只有一行,一个小数ANS(小数点后保留5位)表示Na老师需要消耗的体力期望值. 数

XJOI CSP-S2 2019开放模拟训练题1 赛后总结

比赛链接 友好数对 暴力枚举\([L,R]\)之间的所有数,将每个数进行"旋转",看是否符合题意. 注意"旋转"的次数,并不一定是数字位数.只要旋转回到了初始数就应该跳出,否则会重复计算. #include<bits/stdc++.h> int T,L,R; int F(int x) { int Len=0; while(x){x/=10;Len++;} return Len; } int main() { scanf("%d",&a

【XJOI】【NOI考前模拟赛7】

DP+卡常数+高精度/  计算几何+二分+判区间交/  凸包 首先感谢徐老师的慷慨,让蒟蒻有幸膜拜了学军的神题.祝NOI2015圆满成功 同时膜拜碾压了蒟蒻的众神QAQ 填填填 我的DP比较逗比……(当时看到其他大神有更加优秀的做法) f[i][j]表示前 i 个数,第一行填了 j 个的方案数,那么如果 i 并没有固定位置,f[i][j]=f[i-1][j]+f[i-1][j-1];即 i 这个数放在第一行或是第二行...(废话) 如果 i 固定的位置是第一行(1,y),那么f[i]中只有f[i

xjoi省选模拟赛_14

T1 发现 对于当前 投出 奇数次向上的概率为 p 那么 若加入一个 pi=0.5 的骰子 发现  p奇 +1=p奇 * 0.5+p偶 * 0.5 = p偶+1  也就是说 只要方案中存在一个 p=0.5 的骰子 这个方案必然合法  : 1 #include <bits/stdc++.h> 2 #define N 100 3 #define eps 1e-7 4 using namespace std; 5 typedef long double ldb; 6 int t,n; 7 ldb A

Up to 8% free bonus for runescape 2007 gp on Rsorder as july best gift&Enjoy Telos During 7.1-7.22

Now, a small band of freedom fighters struggle to end the osrs gold  long, dark night of Daein's oppression. The big blog news of the day is that Vox Media has acquired Curbed Network. As an amulet you should be wearing an amulet of glory and if you

2016/2/22 三级导航

1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="

22.Android 十分方便的滑动标签页

22.Android 十分方便的滑动标签页 Android 十分方便的滑动标签页 前言 EasySlidingTabs属性 EasySlidingTabs布局 FragmentPagerAdapter EasySlidingTabs设置Tab背景 Github传送门 效果图 前言 其实滑动标签页是很常见的,网上搜也是一大堆.但是好用.简单.少bug.可扩展的库实在不多.很多想在做滑动标签页的时候也是经常想到各种不靠谱的库,虽然不难,但是容易坑自己. 原三星底层App大神JiangEcho提供技术

Solr4.8.0源码分析(22)之 SolrCloud的Recovery策略(三)

Solr4.8.0源码分析(22)之 SolrCloud的Recovery策略(三) 本文是SolrCloud的Recovery策略系列的第三篇文章,前面两篇主要介绍了Recovery的总体流程,以及PeerSync策略.本文以及后续的文章将重点介绍Replication策略.Replication策略不但可以在SolrCloud中起到leader到replica的数据同步,也可以在用多个单独的Solr来实现主从同步.本文先介绍在SolrCloud的leader到replica的数据同步,下一篇

Siemens.Sinutrain.v6.3.MultiLanguage-ISO 1CD(模拟训练)

Siemens.Simatic.WinCC.v7.0.MultiLanguage-ISO 1DVD(自动化监控组态软件) Siemens.Simatic.WinCC.Web.Navigator.v6.2.SP2.Multilanguage 1CD(提供可视化图形界面,通过网络操控设备的功能, 而不需更换WinCC的项目) Siemens.SIMATIC.WinCC.Flexible.2005.Edition.0406.MultiLanguage-ISO 3CD(适用于所有应用程序的工程软件) S