标签: 模拟

[CF3C]Tic-tac-toe 题解

[CF3C]Tic-tac-toe 题解

题目地址:Codeforces:Problem – 3C – Codeforces、洛谷:CF3C Tic-tac-toe – 洛谷 | 计算机科学教育新生态

题目描述

Certainly, everyone is familiar with tic-tac-toe game. The rules are very simple indeed. Two players take turns marking the cells in a 3 × 3 grid (one player always draws crosses, the other — noughts). The player who succeeds first in placing three of his marks in a horizontal, vertical or diagonal line wins, and the game is finished. The player who draws crosses goes first. If the grid is filled, but neither Xs, nor 0s form the required line, a draw is announced.

You are given a 3 × 3 grid, each grid cell is empty, or occupied by a cross or a nought. You have to find the player (first or second), whose turn is next, or print one of the verdicts below:

  • illegal — if the given board layout can’t appear during a valid game;
  • the first player won — if in the given board layout the first player has just won;
  • the second player won — if in the given board layout the second player has just won;
  • draw — if the given board layout has just let to a draw.

题意简述

给一个井字棋(三子棋)的局面,请判断该局面的状态,状态有以下几种:

  • 下一步X玩家下棋
  • 下一步O玩家下棋
  • 非法状态(正常游戏过程中不会出现的局面)
  • X玩家获胜
  • O玩家获胜
  • 平局

井字棋玩法请百度。

输入输出格式

输入格式:
The input consists of three lines, each of the lines contains characters “.”, “X” or “0” (a period, a capital letter X, or a digit zero).

输出格式:
Print one of the six verdicts: first, second, illegal, the first player won, the second player won or draw.

输入输出样例

输入样例#1:

X0X
.0.
.X.

输出样例#1:

second

题解

大模拟题,细节和分类特别多。分状态讨论符合的情况。

下一步X下棋,仅出现于合法且无人获胜的局面中,特征是局面中X和O的数量相同。
下一步O下棋,仅出现于合法且无人获胜的局面中,特征是局面中X比O的数量多1。
非法状态,有以下几类:X与O的数量的关系既不是相同也不是X比O多1;X获胜之后O仍然下了一步棋(X获胜之后X与O数量相同);O获胜之后X仍然下了一步棋(O获胜之后X比O数量多1)。
X获胜,合法局面中X棋子占据了某一行、列或正副对角线。
O获胜,合法局面中O棋子占据了某一行、列或正副对角线。
平局,合法局面,无人获胜,且棋盘中没有空位。

调试的时候平均一个submission过一个测试点,果然还是我太菜了。

代码

// Code by KSkun, 2019/6
#include <cstdio>

char a[5][5];

int main() {
    scanf("%s%s%s", a[1] + 1, a[2] + 1, a[3] + 1);
    int cntx = 0, cnto = 0;
    bool hasdot = false;
    for(int i = 1; i <= 3; i++) {
        for(int j = 1; j <= 3; j++) {
            if(a[i][j] == 'X') cntx++;
            if(a[i][j] == '0') cnto++;
            if(a[i][j] == '.') hasdot = true;
        }
    }
    if(cntx != cnto && cntx != cnto + 1) {
        puts("illegal"); return 0;
    }
    bool fw = false, sw = false;
    for(int i = 1; i <= 3; i++) {
        if(a[i][1] == a[i][2] && a[i][2] == a[i][3]) {
            if(a[i][1] == 'X') fw = true;
            else if(a[i][1] == '0') sw = true;
        }
    }
    for(int i = 1; i <= 3; i++) {
        if(a[1][i] == a[2][i] && a[2][i] == a[3][i]) {
            if(a[1][i] == 'X') fw = true;
            else if(a[1][i] == '0') sw = true;
        }
    }
    if(a[1][1] == a[2][2] && a[2][2] == a[3][3]) {
        if(a[1][1] == 'X') fw = true;
        else if(a[1][1] == '0') sw = true;
    }
    if(a[1][3] == a[2][2] && a[2][2] == a[3][1]) {
        if(a[1][3] == 'X') fw = true;
        else if(a[1][3] == '0') sw = true;
    }
    if(fw && sw) puts("illegal");
    else if(fw && cntx != cnto + 1) puts("illegal");
    else if(sw && cntx != cnto) puts("illegal");
    else if(fw) puts("the first player won");
    else if(sw) puts("the second player won");
    else if(!hasdot) puts("draw");
    else if(cntx == cnto) puts("first");
    else if(cntx == cnto + 1) puts("second");
    return 0;
}
[工程师死绝的世界C3001]荒れ果てたショップ 翻译及题解

[工程师死绝的世界C3001]荒れ果てたショップ 翻译及题解

荒废的商店

Translation by KSkun

原题:問題「荒れ果てたショップ」 | エンジニアが死滅シタ世界 〜アンドロイドとふたりぼっちで生きろ〜

问题描述

你正在整理商店管理系统的文件。
每个文件有编号与之对应,为了让文件的编号看起来比较一致,比较短的数字需要在左边补0至长度相同。
例如,编号的长度为3时,0应该补成000,而4应该补成004,13补成013,144不需要补0因此就是144,诸如此类。
给你三个整数N、A和B。
你需要将区间[A, B]中的整数补0至长度都为N,然后输出他们。
例如,样例1可以表示为下图。
botchi c 3001 img - [工程师死绝的世界C3001]荒れ果てたショップ 翻译及题解

在这个样例中,你需要将9、10和11三个数字补成长度为3的统一形式。

  • 9是一个一位数,应该在左边补上2个0,这样才能成为长度为3的数字。
  • 10和11是两位数,应该在左边补上1个0,形成长度为3的数字。

输入格式

N A B
  • 整数N表示补成的数字的长度,A和B表示要补的数字的区间。
  • 在输入的最后,包含一个换行符。

输出格式

将区间[A, B]中的每一个整数i补成长度为N的形式并分别输出他们。
输出的最后应该包含一个换行符。

条件

  • 1 ≦ N ≦ 9
  • 0 ≦ A ≦ B ≦ 5000
  • B的数字位数 ≦ N

输入输出样例

输入输出样例1

输入:

3 9 11

输出:

009 
010 
011

输入输出样例2

输入:

2 0 3

输出:

00 
01 
02 
03

题解

// Code by KSkun, 2019/1
#include <cstdio>
#include <cctype>

#include <algorithm>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2)
        ? EOF : *p1++;
}

inline LL readint() {
    LL res = 0, neg = 1; char c = fgc();
    for(; !isdigit(c); c = fgc()) if(c == '-') neg = -1;
    for(; isdigit(c); c = fgc()) res = res * 10 + c - '0';
    return res * neg;
}

inline char readsingle() {
    char c;
    while(!isgraph(c = fgc())) {}
    return c;
}

int n, a, b;
char fmt[10];

int main() {
    n = readint(); a = readint(); b = readint();
    sprintf(fmt, "%%0%dd\n", n);
    for(int i = a; i <= b; i++) {
        printf(fmt, i);
    }
    return 0;
}
[工程师死绝的世界B2001]高層タワー 翻译及题解

[工程师死绝的世界B2001]高層タワー 翻译及题解

高塔

Translation by KSkun

原题:問題「高層タワー」 | エンジニアが死滅シタ世界 〜アンドロイドとふたりぼっちで生きろ〜

问题描述

你在把一些单词组合成新的单词。
新单词由N个字符串按先后顺序结合而成。
为了避免新单词过于冗长,需要将前一个单词的末端与后一个单词的前端最长的相同子串合并起来。
例如,样例1中需要合并paizaappleletter三个单词,
前两个单词paizaapple按要求合并后得到了paizapple这个单词。
再合并上后一个单词就得到了paizappletter

botchi b 2001 img - [工程师死绝的世界B2001]高層タワー 翻译及题解

注意,必须按从前到后的顺序合并,样例2中合并pohpoh时,
pohp合并得到了pohp,此时再合并oh得到的是pohpoh
请按照输入的先后顺序合并给出的N个字符串得到新单词。

输入格式

N 
w_1 
w_2 
... 
w_N
  • 第一行包含一个整数N,表示需要合并的单词数量。
  • 接下来的N行中,第i行给出第i个需要合并的单词字符串w_i。
  • 输入共N + 1行,在输入的最后,包含一个换行符。

输出格式

输出N个单词按输入先后顺序结合成的新单词。

条件

  • 2 ≦ N ≦ 100
  • 对于每个给出的单词字符串w_i,都满足以下条件。
    • 1 ≦ w_i的长度 ≦ 100
    • w_i只由半角小写英文字母构成。

输入输出样例

输入输出样例1

输入:

3 
paiza 
apple 
letter

输出:

paizappletter

输入输出样例2

输入:

3 
poh 
p 
oh

输出:

pohpoh

题解

// Code by KSkun, 2019/1
#include <cstdio>
#include <cctype>
#include <cstring>

#include <algorithm>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2)
        ? EOF : *p1++;
}

inline LL readint() {
    LL res = 0, neg = 1; char c = fgc();
    for(; !isdigit(c); c = fgc()) if(c == '-') neg = -1;
    for(; isdigit(c); c = fgc()) res = res * 10 + c - '0';
    return res * neg;
}

inline char readsingle() {
    char c;
    while(!isgraph(c = fgc())) {}
    return c;
}

const int MAXN = 10005;

int n, rlen = 0, len;
char res[MAXN], w[MAXN];

inline bool issame(int len) {
    for(int i = 1; i <= len; i++) {
        if(res[rlen - (len - i)] != w[i]) return false;
    }
    return true;
}

inline int solve(int len) {
    for(int i = std::min(rlen, len); i >= 1; i--) {
        if(issame(i)) return i;
    }
    return 0;
}

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%s", w + 1);
        len = strlen(w + 1);
        int r = solve(len);
        for(int i = 1; i <= len - r; i++) {
            res[rlen + i] = w[r + i];
        }
        rlen += len - r;
    }
    printf("%s", res + 1);
    return 0;
}