学习编程中的Ben 发表于 2023-8-13 16:56:19

小粉兔 Failed System Test

本帖最后由 学习编程中的Ben 于 2023-8-15 20:38 编辑

# 202308I 小粉兔 Failed System Test

## 题目背景

小粉兔在某场 CF 中 -154,警示大家不能 FST。

这是一道 **hack 题**。在本题目中,你将得到两个问题和两个解决对应问题的代码,但是给出的代码不能对于某些输入给出正确的输出。不能给出正确的输出的情况包括:

1. 输出错误的结果。
2. 运行超时。
3. 产生一些运行时未定义行为。目前技术可检测的未定义行为仅包括数组越界。

对于这两个问题,你需要分别提交一份符合要求的输入数据,使得给定的代码不能给出正确的输出。你可以直接使用『提交答案』功能,也可以提交一份以任何语言写成的数据生成器。

---
**提示:如果你使用提交答案功能,请在提交其他题目时记得将语言改回你所使用的语言。**

## 题目描述

以下给出两个问题的题目描述:

#### 问题 1

给定 $n$ 个元素,标号为 $1, 2, \cdots, n$,你需要标记其中 $k$ 个元素。如果两个元素标号相差 $1$ 则称二者相邻。

请计算出「自身未被标记且有至少一个相邻元素被标记」的元素的**可能的最小数量**和**可能的最大数量**。

#### 问题 2

给定一个仅包含小写字母 `a`、`b`、`c` 的字符串,判断这个字符串是否符合以下所有特征:

1. 字符串中至少有一个 `a` 字母和一个 `b` 字母,且所有的 `a` 在 `b` 之前。
2. 如果字符串中有 `c`,所有的 `a` 在 `b`、`c` 之前,所有的 `b` 在 `c` 之前。
3. `c` 的数量等于 `a` 的数量或 `b` 的数量。

## 输入格式

#### 问题 1

输入共一行两个整数 $n, k$。

#### 问题 2

输入共一行一个字符串 $S$。

## 输出格式

#### 问题 1

输出共一行两个整数,依次代表可能的最小数量和可能的最大数量。

#### 问题 2

输出共一行一个字符串。如果 $S$ 符合要求,则输出 `YES`,否则输出 `NO`。

## 样例 #1

### 样例输入 #1

```
6 3
```

### 样例输出 #1

```
1 3
```

## 样例 #2

### 样例输入 #2

```
aaabccc
```

### 样例输出 #2

```
YES
```

## 提示

### 样例组与实际输入的说明

两个样例分别对应两个问题的样例输入输出。

如果你直接采用『提交答案』的方式,请分别将两个输入数据命名为 `1.in`、`2.in`,并打成 zip 压缩包进行提交;

如果你采用提交数据生成器的方式,你的生成器可以从标准输入读入一个整数 $x$,满足 $1 \leq x \leq 2$,表示该测试点对应的问题编号,然后**输出对应的输入数据**。

显然,你的程序不应该读入『输入格式』里提到的任何内容(而应该构造它们),也不应该输出『样例输出』里提到的任何内容(而是只输出你构造的输入数据)。你不应该使用样例测试你的程序,这只是对两个问题的样例说明。

### 数据规模要求

你给出的数据必须满足如下要求:

1. 完全符合『输入格式』的规定,不能有多余的输入,但是可以有文末回车。
2. 对于问题 $1$,$1 \leq n \leq 10 ^ 9$,$0 \leq k \leq n$。
3. 对于问题 $2$,$1 \leq \left | S \right | \leq 5000$($\left | S \right |$ 代表字符串 $S$ 的长度),$S$ 中仅包含小写字母 `a, b, c`。

### 目标代码

你需要 hack 如下的代码:

#### 问题 1

```cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
    int n, k;
    cin >> n >> k;
        if (k == n || k == 0) {
                cout << "0 0" << endl;
                return 0;
        }
        cout << "1 ";
        if (k * 3 <= n)
      cout << 2 * k << endl;
        else
      cout << n - k << endl;
        return 0;
}
```

#### 问题 2

```cpp
#include <bits/stdc++.h>
using namespace std;

char str;
int i, n, A, B, C;

int main() {
        cin >> str;
        n = strlen(str);
        if (str != 'a') {
                cout << "NO" << endl;
                return 0;
        }
        for (i = 0; i < n; ++i)
      if (str != 'a') break;
        A = i;
        for (; i < n; ++i)
                if (str != 'b') break;
        if (i == n || str != 'c') {
                cout << "NO" << endl;
                return 0;
        }
        B = i - A;
        for (; i < n; ++i)
                if (str != 'c') break;
        if (i != n) {
                cout << "NO" << endl;
                return 0;
        }
        C = n - B - A;
        if (C != A && C != B)
      cout << "NO" << endl;
        else
      cout << "YES" << endl;
        return 0;
}
```

目标代码的编译选项为 `-std=c++14 -fno-asm -O2`。编译器为洛谷提供的 g++。你可以在『在线 IDE』中选择 C++14 语言来获得完全相同的编译环境。

#### 数据判定

你给出的数据必须完全符合『数据规模要求』,否则将得到 Unaccepted 的结果。

#### 超时判定

程序每执行若干条指令,我们会检测一遍程序的运行时间。我们保证两次检测之间的指令条数是一个输入规模无关的量,也即每执行 $O(1)$ 条指令会进行一次检测。且两次检测之间的指令条数不会太多,一般不超过 $100$ 条 C++ 语句。

如果程序的运行时间超过 $500 \text{ms}$,则判定为程序运行超时,返回 accepted 结果。

#### 结果错误判定

如果程序在规定的时间内结束且给出了一个输出,我们会比较这个输出和**完全正确的输出**,如果二者不同,则判定为 hack 成功,返回 accepted 结果。

#### 未定义行为判定

我们会在每次**显式**的调用数组元素前判断数组下标是否超过数组范围,如果超过,则判定为 hack 成功,返回 accepted 结果。

这就是说,如果你希望通过未定义行为进行 hack,只能对显式的调用数组元素的行为进行 hack。

### 样例程序

这是一份可以帮你理解你需要输出的内容的样例程序,**但它不能给出正确的 hack 数据**。直接提交此程序不会得分。

```cpp
#include <iostream>

using namespace std;

int main() {
int taskId;
cin >> taskId;
if (taskId == 1) {
    cout << "" <<endl;
} else if (taskId == 2) {
    cout << "" << endl;
} else { // 这个 else 不会被执行
    cout << "Stupid Fusu!" << endl;
}
}
```

如果你使用『提交答案』功能,请务必保证打开压缩包后能且仅能**直接**看到两个 `.in` 文件。这就是说,文件结构必须是:

```plain
ans.zip
|---1.in
|---2.in
```

两个文件不应该被额外的文件夹包含,即文件结构不能是:

```plain
ans.zip
|---ans(folder)
      |---1.in
      |---2.in
```

### 关于评测信息的说明

如果 hack 成功,对应测试点的信息为 accepted。如果返回其他信息,说明程序本身有误。

例如,如果返回 TLE,不代表成功的将对应程序 hack 至超时,而是表示数据生成器本身运行超时,测试点不得分。

特别的,返回 UKE 结果可能是数据不合法(有多余内容、缺少内容或数据范围不符合要求)。




啊啊啊啊啊啊啊啊啊我服了啊,根本就照不出来好吧

isdkz 发表于 2023-8-13 16:56:43

这道题目是一道hack题,你需要找出给定的代码的漏洞,并构造输入数据使其输出错误结果。

问题1的代码中,首先判断如果k等于n或者k等于0,则输出"0 0"。然后根据条件判断输出最小数量和最大数量。如果k的3倍小于等于n,则最小数量为1,最大数量为2k;否则最小数量为1,最大数量为n-k。

问题2的代码中,首先读入一个字符串S。然后根据条件判断输出"YES"或者"NO"。具体的判断逻辑是,首先判断S的第一个字符是否为'a',如果不是则输出"NO"。然后遍历S,找到第一个不为'a'的字符的位置,记为A。继续遍历S,找到第一个不为'b'的字符的位置,记为B。如果此时B的位置不为c,则输出"NO"。最后,判断S剩余的字符数是否等于B-A的值,如果不相等,则输出"NO";否则输出"YES"。

要hack这两个问题的代码,你需要构造输入数据使其输出错误结果。具体的构造方法需要根据代码的漏洞进行分析。

陶远航 发表于 2023-8-13 16:56:52

你好!根据题目描述,我会逐步给出问题1和问题2的输入数据。

问题1输入数据:6 3
解释:有6个元素,需要标记其中3个元素。

问题2输入数据:aaabccc
解释:给定的字符串为"aaabccc"。

请注意,以上是问题的输入数据,你需要将它们保存在不同的文件中,并按照要求进行命名。
如果问题已经解决,请设置最佳答案

学习编程中的Ben 发表于 2023-8-13 16:59:25

isdkz 发表于 2023-8-13 16:56
这道题目是一道hack题,你需要找出给定的代码的漏洞,并构造输入数据使其输出错误结果。

问题1的代码中 ...

靠,你倒是分析啊

学习编程中的Ben 发表于 2023-8-13 17:03:21

陶远航 发表于 2023-8-13 16:56
你好!根据题目描述,我会逐步给出问题1和问题2的输入数据。

问题1输入数据:6 3


啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊,不对啊

陶远航 发表于 2023-8-13 17:11:42

学习编程中的Ben 发表于 2023-8-13 17:03
啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊,不对啊

首先,我们来看问题 1。这个问题的目标代码有一个逻辑错误,它没有考虑到 k 个元素可能不连续的情况。例如,如果 n = 6, k = 2,并且标记了第 1 和第 6 个元素,那么最小数量应该是 0,而不是 1。因此,我们可以构造一个输入数据,使得 k 个元素不连续,并且最小数量和最大数量都不等于目标代码的输出。一个可能的输入数据是:

6 2

对于这个输入数据,正确的输出应该是:

0 4

而目标代码的输出是:

1 2

所以这个输入数据可以 hack 成功。

接下来,我们来看问题 2。这个问题的目标代码有一个数组越界的错误,它没有检查字符串是否为空。如果输入一个空字符串,那么 str 就会访问到不存在的元素,导致未定义行为。因此,我们可以构造一个输入数据,就是一个空字符串:



对于这个输入数据,正确的输出应该是:

NO

而目标代码的输出是:

Runtime Error: Array Index Out Of Bounds

所以这个输入数据也可以 hack 成功。

以上就是我为你解答这道 hack 题的过程。我希望你能从中学习到一些 hack 的思路和方法。如果你还有其他关于 hack 题的问题,欢迎继续和我交流。

完熟マンゴー 发表于 2023-8-16 11:04:08

{:10_254:}

琅琊王朝 发表于 2023-8-16 12:01:18

{:9_241:}

sfqxx 发表于 2023-9-3 11:45:01

陶远航 发表于 2023-8-13 17:11
首先,我们来看问题 1。这个问题的目标代码有一个逻辑错误,它没有考虑到 k 个元素可能不连续的情况。例 ...

不能空
页: [1]
查看完整版本: 小粉兔 Failed System Test