「解题报告」NOIP 2020
总分:90 + 32 + 5 + 35 = 162。
[NOIP2020] 排水系统
题目描述
对于一个城市来说,排水系统是极其重要的一个部分。
有一天,小 C 拿到了某座城市排水系统的设计图。排水系统由 \(n\) 个排水结点(它们从 \(1 \sim n\) 编号)和若干个单向排水管道构成。每一个排水结点有若干个管道用于汇集其他排水结点的污水(简称为该结点的汇集管道),也有若干个管道向其他的排水结点排出污水(简称为该结点的排出管道)。
排水系统的结点中有 \(m\) 个污水接收口,它们的编号分别为 \(1, 2, \ldots , m\),污水只能从这些接收口流入排水系统,并且这些结点没有汇集管道。排水系统中还有若干个最终排水口,它们将污水运送到污水处理厂,没有排出管道的结点便可视为一个最终排水口。
现在各个污水接收口分别都接收了 \(1\) 吨污水,污水进入每个结点后,会均等地从当前结点的每一个排出管道流向其他排水结点,而最终排水口将把污水排出系统。
现在小 C 想知道,在该城市的排水系统中,每个最终排水口会排出多少污水。该城市的排水系统设计科学,管道不会形成回路,即不会发生污水形成环流的情况。
输入格式
第一个两个用单个空格分隔的整数 \(n, m\)。分别表示排水结点数与接收口数量。
接下来 \(n\) 行,第 \(i\) 行用于描述结点 \(i\) 的所有排出管道。其中每行第一个整数 \(d_i\) 表示其排出管道的数量,接下来 \(d_i\) 个用单个空格分隔的整数 \(a_1, a_2, \ldots , a_{d_i}\) 依次表示管道的目标排水结点。
保证不会出现两条起始结点与目标结点均相同的管道。
输出格式
输出若干行,按照编号从小到大的顺序,给出每个最终排水口排出的污水体积。其中体积使用分数形式进行输出,即每行输出两个用单个空格分隔的整数 \(p\),\(q\),表示排出的污水体积为 \(\frac{p}{q}\)。要求 \(p\) 与 \(q\) 互素,\(q = 1\) 时也需要输出 \(q\)。
样例 #1
样例输入 #1
5 1
3 2 3 5
2 4 5
2 5 4
0
0
样例输出 #1
1 3
2 3
样例 #2
样例输入 #2
见附件中的 water/water2.in
样例输出 #2
见附件中的 water/water2.ans
样例 #3
样例输入 #3
见附件中的 water/water3.in
样例输出 #3
见附件中的 water/water3.ans
提示
【样例 #1 解释】
\(1\) 号结点是接收口,\(4, 5\) 号结点没有排出管道,因此是最终排水口。
\(1\) 吨污水流入 \(1\) 号结点后,均等地流向 \(2, 3, 5\) 号结点,三个结点各流入 \(\frac{1}{3}\) 吨污水。
\(2\) 号结点流入的 \(\frac{1}{3}\) 吨污水将均等地流向 \(4, 5\) 号结点,两结点各流入 \(\frac{1}{6}\) 吨污水。
\(3\) 号结点流入的 \(\frac{1}{3}\) 吨污水将均等地流向 \(4, 5\) 号结点,两结点各流入 \(\frac{1}{6}\) 吨污水。
最终,\(4\) 号结点排出 \(\frac{1}{6} + \frac{1}{6} = \frac{1}{3}\) 吨污水,\(5\) 号结点排出 \(\frac{1}{3} + \frac{1}{6} + \frac{1}{6} = \frac{2}{3}\) 吨污水。
【数据范围】
测试点编号 | \(n \le\) | \(m \le\) |
---|---|---|
\(1 \sim 3\) | \(10\) | \(1\) |
\(4 \sim 6\) | \({10}^3\) | \(1\) |
\(7 \sim 8\) | \({10}^5\) | \(1\) |
\(9 \sim 10\) | \({10}^5\) | \(10\) |
对于全部的测试点,保证 \(1 \le n \le {10}^5\),\(1 \le m \le 10\),\(0 \le d_i \le 5\)。
数据保证,污水在从一个接收口流向一个最终排水口的过程中,不会经过超过 \(10\) 个中间排水结点(即接收口和最终排水口不算在内)。
拓扑排序,但是只有 \(90\) 分,因为最后一个点要写高精(考场上有时间写高精去拿这十分倒不如去打后面题的暴力 其次我是不会告诉你我已经不会写高精了)。
// The code was written by yifan, and yifan is neutral!!!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define bug puts("NOIP rp ++!");
#define rep(i, a, b, c) for (int i = (a); i <= (b); i += (c))
#define per(i, a, b, c) for (int i = (a); i >= (b); i -= (c))
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 1e5 + 5;
int n, m;
int in[N], out[N];
vector<int> e[N];
bool watout[N];
queue<int> q;
struct dfrac {
ll fz, fm;
} water[N];
ll gcd(ll x, ll y) {
if (!y) {
return x;
}
return gcd(y, x % y);
}
dfrac operator+ (dfrac a, dfrac b) {
ll fza = a.fz, fma = a.fm, fzb = b.fz, fmb = b.fm;
ll lcm = fma / gcd(fma, fmb) * fmb;
ll g1 = lcm / fma, g2 = lcm / fmb;
fza *= g1, fzb *= g2;
ll fz = fza + fzb, fm = lcm;
ll g = gcd(fz, fm);
fz /= g, fm /= g;
return dfrac{fz, fm};
}
dfrac operator* (dfrac a, dfrac b) {
ll fza = a.fz, fma = a.fm, fzb = b.fz, fmb = b.fm;
ll g1 = gcd(fza, fmb), g2 = gcd(fma, fzb);
fza /= g1, fmb /= g1;
fma /= g2, fzb /= g2;
return dfrac{fza * fzb, fma * fmb};
}
void topsort() {
while (!q.empty()) {
int u = q.front();
q.pop();
dfrac w = water[u] * dfrac{1, out[u]};
for (int v : e[u]) {
water[v] = water[v] + w;
-- in[v];
if (!in[v]) {
q.emplace(v);
}
}
}
}
int main() {
n = read<int>(), m = read<int>();
int d, x;
rep (i, 1, n, 1) {
d = read<int>();
out[i] = d;
rep (j, 1, d, 1) {
x = read<int>();
++ in[x];
e[i].emplace_back(x);
}
}
rep (i, 1, n, 1) {
if (!in[i]) {
water[i] = {1, 1};
q.emplace(i);
} else {
water[i] = {0, 1};
}
if (!out[i]) {
watout[i] = 1;
}
}
topsort();
ll fz, fm, g;
rep (i, 1, n, 1) {
if (watout[i]) {
fz = water[i].fz, fm = water[i].fm;
g = gcd(fz, fm);
cout << fz / g << ' ' << fm / g << '\n';
}
}
return 0;
}
[NOIP2020] 字符串匹配
题目描述
小 C 学习完了字符串匹配的相关内容,现在他正在做一道习题。
对于一个字符串 \(S\),题目要求他找到 \(S\) 的所有具有下列形式的拆分方案数:
\(S = ABC\),\(S = ABABC\),\(S = ABAB \ldots ABC\),其中 \(A\),\(B\),\(C\) 均是非空字符串,且 \(A\) 中出现奇数次的字符数量不超过 \(C\) 中出现奇数次的字符数量。
更具体地,我们可以定义 \(AB\) 表示两个字符串 \(A\),\(B\) 相连接,例如 \(A = \texttt{aab}\),\(B = \texttt{ab}\),则 \(AB = \texttt{aabab}\)。
并递归地定义 \(A^1=A\),\(A^n = A^{n - 1} A\)(\(n \ge 2\) 且为正整数)。例如 \(A = \texttt{abb}\),则 \(A^3=\texttt{abbabbabb}\)。
则小 C 的习题是求 \(S = {(AB)}^iC\) 的方案数,其中 \(F(A) \le F(C)\),\(F(S)\) 表示字符串 \(S\) 中出现奇数次的字符的数量。两种方案不同当且仅当拆分出的 \(A\)、\(B\)、\(C\) 中有至少一个字符串不同。
小 C 并不会做这道题,只好向你求助,请你帮帮他。
输入格式
本题有多组数据,输入文件第一行一个正整数 \(T\) 表示数据组数。
每组数据仅一行一个字符串 \(S\),意义见题目描述。\(S\) 仅由英文小写字母构成。
输出格式
对于每组数据输出一行一个整数表示答案。
样例 #1
样例输入 #1
3
nnrnnr
zzzaab
mmlmmlo
样例输出 #1
8
9
16
样例 #2
样例输入 #2
5
kkkkkkkkkkkkkkkkkkkk
lllllllllllllrrlllrr
cccccccccccccxcxxxcc
ccccccccccccccaababa
ggggggggggggggbaabab
样例输出 #2
156
138
138
147
194
样例 #3
样例输入 #3
见附件中的 string/string3.in
样例输出 #3
见附件中的 string/string3.ans
样例 #4
样例输入 #4
见附件中的 string/string4.in
样例输出 #4
见附件中的 string/string4.ans
提示
【样例 #1 解释】
对于第一组数据,所有的方案为
- \(A=\texttt{n}\),\(B=\texttt{nr}\),\(C=\texttt{nnr}\)。
- \(A=\texttt{n}\),\(B=\texttt{nrn}\),\(C=\texttt{nr}\)。
- \(A=\texttt{n}\),\(B=\texttt{nrnn}\),\(C=\texttt{r}\)。
- \(A=\texttt{nn}\),\(B=\texttt{r}\),\(C=\texttt{nnr}\)。
- \(A=\texttt{nn}\),\(B=\texttt{rn}\),\(C=\texttt{nr}\)。
- \(A=\texttt{nn}\),\(B=\texttt{rnn}\),\(C=\texttt{r}\)。
- \(A=\texttt{nnr}\),\(B=\texttt{n}\),\(C=\texttt{nr}\)。
- \(A=\texttt{nnr}\),\(B=\texttt{nn}\),\(C=\texttt{r}\)。
【数据范围】
测试点编号 | \(\lvert S \rvert \le\) | 特殊性质 |
---|---|---|
\(1 \sim 4\) | \(10\) | 无 |
\(5 \sim 8\) | \(100\) | 无 |
\(9 \sim 12\) | \(1000\) | 无 |
\(13 \sim 14\) | \(2^{15}\) | \(S\) 中只包含一种字符 |
\(15 \sim 17\) | \(2^{16}\) | \(S\) 中只包含两种字符 |
\(18 \sim 21\) | \(2^{17}\) | 无 |
\(22 \sim 25\) | \(2^{20}\) | 无 |
对于所有测试点,保证 \(1 \le T \le 5\),\(1 \le |S| \le 2^{20}\)。
用 string
乱搞,最后得到了 \(32\) 分的好成绩,大概是个 \(O_{n^4}\) 的做法。
// The code was written by yifan, and yifan is neutral!!!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define bug puts("NOIP rp ++!");
#define rep(i, a, b, c) for (int i = (a); i <= (b); i += (c))
#define per(i, a, b, c) for (int i = (a); i >= (b); i -= (c))
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
int f(string s) {
int num[26], cnt = 0;
memset(num, 0, sizeof num);
for (char c : s) {
++ num[c - 'a'];
}
rep (i, 0, 25, 1) {
if (num[i] & 1) {
++ cnt;
}
}
return cnt;
}
int T;
string str;
void solve() {
int ans = 0;
cin >> str;
int len = str.size();
rep (i, 1, len - 2, 1) {
string C = str.substr(len - i, i);
string ABi = str.substr(0, len - i);
rep (j, 2, len - i, 1) {
if ((len - i) % j != 0) continue ;
string AB = ABi.substr(0, j), tmp = "";
int K = (len - i) / j;
rep (k, 1, K, 1) {
tmp += AB;
}
if (tmp != ABi) continue ;
rep (k, 1, j - 1, 1) {
string A = AB.substr(0, k);
string B = AB.substr(k, j - k);
if (f(A) <= f(C)) {
++ ans;
}
}
}
}
cout << ans << '\n';
}
int main() {
T = read<int>();
while (T --) {
solve();
}
return 0;
}
[NOIP2020] 移球游戏
题目描述
小 C 正在玩一个移球游戏,他面前有 \(n + 1\) 根柱子,柱子从 \(1 \sim n + 1\) 编号,其中 \(1\) 号柱子、\(2\) 号柱子、……、\(n\) 号柱子上各有 \(m\) 个球,它们自底向上放置在柱子上,\(n + 1\) 号柱子上初始时没有球。这 \(n \times m\) 个球共有 \(n\) 种颜色,每种颜色的球各 \(m\) 个。
初始时一根柱子上的球可能是五颜六色的,而小 C 的任务是将所有同种颜色的球移到同一根柱子上,这是唯一的目标,而每种颜色的球最后放置在哪根柱子则没有限制。
小 C 可以通过若干次操作完成这个目标,一次操作能将一个球从一根柱子移到另一根柱子上。更具体地,将 \(x\) 号柱子上的球移动到 \(y\) 号柱子上的要求为:
- \(x\) 号柱子上至少有一个球;
- \(y\) 号柱子上至多有 \(m - 1\) 个球;
- 只能将 \(x\) 号柱子最上方的球移到 \(y\) 号柱子的最上方。
小 C 的目标并不难完成,因此他决定给自己加加难度:在完成目标的基础上,使用的操作次数不能超过 \(820000\)。换句话说,小 C 需要使用至多 \(820000\) 次操作完成目标。
小 C 被难住了,但他相信难不倒你,请你给出一个操作方案完成小 C 的目标。合法的方案可能有多种,你只需要给出任意一种,题目保证一定存在一个合法方案。
输入格式
第一行两个用空格分隔的整数 \(n, m\)。分别表示球的颜色数、每种颜色球的个数。
接下来 \(n\) 行每行 \(m\) 个用单个空格分隔的整数,第 \(i\) 行的整数按自底向上的顺序依次给出了 \(i\) 号柱子上的球的颜色。
输出格式
本题采用自定义校验器(special judge)评测。
你的输出的第一行应该仅包含单个整数 \(k\),表示你的方案的操作次数。你应保证 \(0 \le k \le 820000\)。
接下来 \(k\) 行每行你应输出两个用单个空格分隔的正整数 \(x, y\),表示这次操作将 \(x\) 号柱子最上方的球移动到 \(y\) 号柱子最上方。你应保证 \(1 \le x, y \le n + 1\) 且 \(x \ne y\)。
样例 #1
样例输入 #1
2 3
1 1 2
2 1 2
样例输出 #1
6
1 3
2 3
2 3
3 1
3 2
3 2
样例 #2
样例输入 #2
见附件中的 ball/ball2.in
样例输出 #2
见附件中的 ball/ball2.ans
样例 #3
样例输入 #3
见附件中的 ball/ball3.in
样例输出 #3
见附件中的 ball/ball3.ans
提示
【样例 #1 解释】
柱子中的内容为:按自底向上的顺序依次给出柱子上每个球的颜色。
操作 | \(1\) 号柱子 | \(2\) 号柱子 | \(3\) 号柱子 |
---|---|---|---|
初始 | \(1\ 1\ 2\) | \(2\ 1\ 2\) | |
\(1\ 3\) | \(1\ 1\) | \(2\ 1\ 2\) | \(2\) |
\(2\ 3\) | \(1\ 1\) | \(2\ 1\) | \(2\ 2\) |
\(2\ 3\) | \(1\ 1\) | \(2\) | \(2\ 2\ 1\) |
\(3\ 1\) | \(1\ 1\ 1\) | \(2\) | \(2\ 2\) |
\(3\ 2\) | \(1\ 1\ 1\) | \(2\ 2\) | \(2\) |
\(3\ 2\) | \(1\ 1\ 1\) | \(2\ 2\ 2\) |
【数据范围】
测试点编号 | \(n \le\) | \(m \le\) |
---|---|---|
\(1 \sim 2\) | \(2\) | \(20\) |
\(3 \sim 5\) | \(10\) | \(20\) |
\(6 \sim 8\) | \(50\) | \(85\) |
\(9 \sim 14\) | \(50\) | \(300\) |
\(15 \sim 20\) | \(50\) | \(400\) |
对于所有测试点,保证 \(2 \le n \le 50\),\(2 \le m \le 400\)。
【校验器】
为了方便选手测试,在附件中的 ball
目录下我们下发了 checker.cpp
文件,选手可以编译该程序,并使用它校验自己的输出文件。但请注意它与最终评测时所使用的校验器并不完全一致。你也不需要关心其代码的具体内容。
编译命令为:g++ checker.cpp −o checker -std=c++11
。
checker
的使用方式为:checker <inputfile> <outputfile>
,参数依次表示输入文件与你的输出文件。
若你输出的数字大小范围不合法,则校验器会给出相应提示。若你的输出数字大小范围正确,但方案错误,则校验器会给出简要的错误信息:
A x
,表示进行到第 \(x\) 个操作时不合法。B x
,表示操作执行完毕后第 \(x\) 个柱子上的球不合法。
若你的方案正确,校验器会给出 OK
。
不知道为什么总会想起喵了个喵
奔着 \(10\) 分的暴力去的,即 \(n = 2\) 的情况,结果第一次交的时候只有 \(5\) 分,有个处理有点错误,改正后就是 \(10\) 分了。
// The code was written by yifan, and yifan is neutral!!!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define bug puts("NOIP rp ++!");
#define rep(i, a, b, c) for (int i = (a); i <= (b); i += (c))
#define per(i, a, b, c) for (int i = (a); i >= (b); i -= (c))
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 55;
const int M = 410;
const int K = 820010;
using tii = tuple<int, int>;
int n, m, ans;
vector<int> st[N];
int cnt[N][M];
tii step[K];
void work1() {
int col = st[2].back(), c;
while (st[1].back() == col) {
c = st[1].back();
st[3].emplace_back(c);
st[1].pop_back();
-- cnt[1][c];
++ cnt[3][c];
++ ans;
step[ans] = make_tuple(1, 3);
}
while (st[2].back() == col) {
c = st[2].back();
st[3].emplace_back(c);
st[2].pop_back();
-- cnt[2][c];
++ cnt[3][c];
++ ans;
step[ans] = make_tuple(2, 3);
}
}
void getans() {
int x;
while (!st[2].empty()) {
x = st[2].back();
st[1].emplace_back(x);
st[2].pop_back();
++ ans;
step[ans] = make_tuple(2, 1);
}
}
void print() {
cout << ans << '\n';
rep (i, 1, ans, 1) {
cout << get<0>(step[i]) << ' ' << get<1>(step[i]) << '\n';
}
}
void work2() {
while (cnt[1][st[3].front()]) {
if (st[1].back() != st[3].front()) {
if (st[2].size() < m - 1) {
st[2].emplace_back(st[1].back());
-- cnt[1][st[1].back()];
++ cnt[2][st[1].back()];
st[1].pop_back();
++ ans;
step[ans] = make_tuple(1, 2);
} else {
st[3].emplace_back(st[1].back());
-- cnt[1][st[1].back()];
++ cnt[3][st[1].back()];
st[1].pop_back();
++ ans;
step[ans] = make_tuple(1, 3);
}
} else {
if (st[2].size() >= m - 1) {
st[2].emplace_back(st[1].back());
++ cnt[2][st[1].back()];
-- cnt[1][st[1].back()];
st[1].pop_back();
++ ans;
step[ans] = make_tuple(1, 2);
while (st[3].back() != st[3].front()) {
++ ans;
step[ans] = make_tuple(3, 1);
st[1].emplace_back(st[3].back());
++ cnt[1][st[3].back()];
-- cnt[3][st[3].back()];
st[3].pop_back();
}
++ ans;
step[ans] = make_tuple(2, 3);
st[3].emplace_back(st[2].back());
++ cnt[3][st[2].back()];
-- cnt[2][st[2].back()];
st[2].pop_back();
} else {
st[3].emplace_back(st[1].back());
++ cnt[3][st[1].back()];
-- cnt[1][st[1].back()];
st[1].pop_back();
}
}
}
}
void work3() {
int u;
while (!st[2].empty()) {
u = st[2].back();
if (u == st[3].front()) {
++ ans;
step[ans] = make_tuple(2, 3);
st[2].pop_back();
} else {
++ ans;
step[ans] = make_tuple(2, 1);
st[2].pop_back();
}
}
}
int main() {
n = read<int>(), m = read<int>();
int col;
rep (i, 1, n, 1) {
rep (j, 1, m, 1) {
col = read<int>();
st[i].emplace_back(col);
++ cnt[i][col];
}
}
work1();
if (cnt[3][st[3].back()] == m) {
getans();
print();
return 0;
}
work2();
work3();
print();
return 0;
}
[NOIP2020] 微信步数
题目描述
小 C 喜欢跑步,并且非常喜欢在微信步数排行榜上刷榜,为此他制定了一个刷微信步数的计划。
他来到了一处空旷的场地,处于该场地中的人可以用 \(k\) 维整数坐标 \((a_1, a_2, \ldots , a_k)\) 来表示其位置。场地有大小限制,第 \(i\) 维的大小为 \(w_i\),因此处于场地中的人其坐标应满足 \(1 \le a_i \le w_i\)(\(1 \le i \le k\))。
小 C 打算在接下来的 \(P = w_1 \times w_2 \times \cdots \times w_k\) 天中,每天从场地中一个新的位置出发,开始他的刷步数计划(换句话说,他将会从场地中每个位置都出发一次进行计划)。
他的计划非常简单,每天按照事先规定好的路线行进,每天的路线由 \(n\) 步移动构成,每一步可以用 \(c_i\) 与 \(d_i\) 表示:若他当前位于 \((a_1, a_2, \ldots , a_{c_i}, \ldots, a_k)\),则这一步他将会走到 \((a_1, a_2, \ldots , a_{c_i} + d_i, \ldots , a_k)\),其中 \(1 \le c_i \le k\),\(d_i \in \{-1, 1\}\)。小 C 将会不断重复这个路线,直到他走出了场地的范围才结束一天的计划。(即走完第 \(n\) 步后,若小 C 还在场内,他将回到第 \(1\) 步从头再走一遍)。
小 C 对自己的速度非常有自信,所以他并不在意具体耗费的时间,他只想知道 \(P\) 天之后,他一共刷出了多少步微信步数。请你帮他算一算。
输入格式
第一行两个用单个空格分隔的整数 \(n, k\)。分别表示路线步数与场地维数。
接下来一行 \(k\) 个用单个空格分隔的整数 \(w_i\),表示场地大小。
接下来 \(n\) 行每行两个用单个空格分隔的整数 \(c_i, d_i\),依次表示每一步的方向,具体意义见题目描述。
输出格式
仅一行一个整数表示答案。答案可能很大,你只需要输出其对 \({10}^9 + 7\) 取模后的值。
若小 C 的计划会使得他在某一天在场地中永远走不出来,则输出一行一个整数 \(-1\)。
样例 #1
样例输入 #1
3 2
3 3
1 1
2 -1
1 1
样例输出 #1
21
样例 #2
样例输入 #2
5 4
6 8 6 5
3 1
2 1
1 1
2 1
2 -1
样例输出 #2
10265
样例 #3
样例输入 #3
见附件中的 walk/walk3.in
样例输出 #3
见附件中的 walk/walk3.ans
样例 #4
样例输入 #4
见附件中的 walk/walk4.in
样例输出 #4
见附件中的 walk/walk4.ans
提示
【样例 #1 解释】
从 \((1, 1)\) 出发将走 \(2\) 步,从 \((1, 2)\) 出发将走 \(4\) 步,从 \((1, 3)\) 出发将走 \(4\) 步。
从 \((2, 1)\) 出发将走 \(2\) 步,从 \((2, 2)\) 出发将走 \(3\) 步,从 \((2, 3)\) 出发将走 \(3\) 步。
从 \((3, 1)\) 出发将走 \(1\) 步,从 \((3, 2)\) 出发将走 \(1\) 步,从 \((3, 3)\) 出发将走 \(1\) 步。
共计 \(21\) 步。
【数据范围】
测试点编号 | \(n \le\) | \(k \le\) | \(w_i \le\) |
---|---|---|---|
\(1 \sim 3\) | \(5\) | \(5\) | \(3\) |
\(4 \sim 6\) | \(100\) | \(3\) | \(10\) |
\(7 \sim 8\) | \({10}^5\) | \(1\) | \({10}^5\) |
\(9 \sim 12\) | \({10}^5\) | \(2\) | \({10}^6\) |
\(13 \sim 16\) | \(5 \times {10}^5\) | \(10\) | \({10}^6\) |
\(17 \sim 20\) | \(5 \times {10}^5\) | \(3\) | \({10}^9\) |
对于所有测试点,保证 \(1 \le n \le 5 \times {10}^5\),\(1 \le k \le 10\),\(1 \le w_i \le {10}^9\),\(d_i \in \{-1, 1\}\)。
好好的一个题让我做成大模拟
\(O_{n^5}\) 的暴力,加上判断 \(-1\) 的情况,最后得到了 \(35\) 分的好成绩。
// The code was written by yifan, and yifan is neutral!!!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define bug puts("NOIP rp ++!");
#define rep(i, a, b, c) for (int i = (a); i <= (b); i += (c))
#define per(i, a, b, c) for (int i = (a); i >= (b); i -= (c))
template<typename T>
inline T read() {
T x = 0;
bool fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
}
const int N = 5e5 + 5;
const int K = 15;
const int mod = 1e9 + 7;
int n, k;
ll ans;
ll w[K];
int c[N], d[N], change[K];
bool check(int i1, int i2, int i3, int i4, int i5) {
if (i5 == -1e9) {
if (i4 == -1e9) {
if (i3 == -1e9) {
if (i2 == -1e9) {
if (i1 < 1 || i1 > w[1]) {
return 0;
} else {
return 1;
}
} else {
if ((i1 < 1 || i1 > w[1]) || (i2 < 1 || i2 > w[2])) {
return 0;
} else {
return 1;
}
}
} else {
if ((i1 < 1 || i1 > w[1]) || (i2 < 1 || i2 > w[2]) || (i3 < 1 || i3 > w[3])) {
return 0;
} else {
return 1;
}
}
} else {
if ((i1 < 1 || i1 > w[1]) || (i2 < 1 || i2 > w[2]) || (i3 < 1 || i3 > w[3]) || (i4 < 1 || i4 > w[4])) {
return 0;
} else {
return 1;
}
}
} else {
if ((i1 < 1 || i1 > w[1]) || (i2 < 1 || i2 > w[2]) || (i3 < 1 || i3 > w[3]) || (i4 < 1 || i4 > w[4]) || (i5 < 1 || i5 > w[5])) {
return 0;
} else {
return 1;
}
}
}
void dfs(int i1, int i2, int i3, int i4, int i5) {
int cnt = 0;
while (check(i1, i2, i3, i4, i5)) {
rep (i, 1, n, 1) {
if (c[i] == 1) {
i1 += d[i];
}
if (c[i] == 2) {
i2 += d[i];
}
if (c[i] == 3) {
i3 += d[i];
}
if (c[i] == 4) {
i4 += d[i];
}
if (c[i] == 5) {
i5 += d[i];
}
++ ans;
ans %= mod;
if (!check(i1, i2, i3, i4, i5)) {
break ;
}
}
}
}
int main() {
n = read<int>(), k = read<int>();
rep (i, 1, k, 1) {
w[i] = read<int>();
}
rep (i, 1, n, 1) {
c[i] = read<int>(), d[i] = read<int>();
change[c[i]] += d[i];
}
int fg = 1;
rep (i, 1, k, 1) {
fg = (fg & (!change[i]));
}
if (fg) {
puts("-1");
return 0;
}
rep (i1, 1, w[1], 1) {
if (k >= 2) {
rep (i2, 1, w[2], 1) {
if (k >= 3) {
rep (i3, 1, w[3], 1) {
if (k >= 4) {
rep (i4, 1, w[4], 1) {
if (k >= 5) {
rep (i5, 1, w[5], 1) {
dfs(i1, i2, i3, i4, i5);
}
} else {
dfs(i1, i2, i3, i4, -1e9);
}
}
} else {
dfs(i1, i2, i3, -1e9, -1e9);
}
}
} else {
dfs(i1, i2, -1e9, -1e9, -1e9);
}
}
} else {
dfs(i1, -1e9, -1e9, -1e9, -1e9);
}
}
cout << ans << '\n';
return 0;
}