[ARC058E] 和風いろはちゃん
题意
-
若 \(a = \{a_1, a_2, \cdots a_n\}\) 存在 \(1 \le x < y < z < w \le n + 1\) 满足 \(\sum \limits_{i = x} ^ {y - 1} a_i = X, \sum \limits_{i = y} ^ {z - 1} a_i = Y, \sum \limits_{i = z} ^ {w - 1}a_i = Z\) 时,则称数列 \(a\) 是 好的。
-
求在所有长度为 \(n\) 且 \(a_i \in \mathbb{N} ^ {+} \cap [1, 10]\) 的 \(10 ^ n\) 个序列 \(a\) 中,有多少个序列是 好的,答案对 \(10 ^ 9 + 7\) 取模。
-
\(3 \le n \le 40\),\(1 \le X \le 5\),\(1 \le Y \le 7\),\(1 \le Z \le 5\)。
Sol
注意到 \(x + y + z \le 17\),因此考虑将这一段的和状压下来。
发现我们并不关心这一段的长度。
所以我们考虑直接在 \(2 ^ {z - 1}, 2 ^ {y + z - 1}, 2 ^ {x + y + z - 1}\) 将值记下来。
那么转移就很显然了,考虑当前的数字是 \(k\),那么直接将前 \(k\) 位删掉,在最后加上 \(k\) 位即可。
Code
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <tuple>
#define int long long
#define tupl tuple <int, int, int>
using namespace std;
#ifdef ONLINE_JUDGE
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;
#endif
int read() {
int p = 0, flg = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') flg = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
p = p * 10 + c - '0';
c = getchar();
}
return p * flg;
}
void write(int x) {
if (x < 0) {
x = -x;
putchar('-');
}
if (x > 9) {
write(x / 10);
}
putchar(x % 10 + '0');
}
const int N = 3e5 + 5, mod = 1e9 + 7;
array <array <int, N>, 45> f;
int pow_(int x, int k, int p) {
int ans = 1;
while (k) {
if (k & 1) ans = ans * x % p;
x = x * x % p;
k >>= 1;
}
return ans;
}
void Mod(int &x) {
if (x >= mod) x -= mod;
if (x < 0) x += mod;
}
bool check(int T, tupl qrl) {
if (~T & (1 << (get <2>(qrl) - 1)) ||
~T & (1 << (get <1>(qrl) + get <2>(qrl) - 1)) ||
~T & (1 << (get <0>(qrl) + get <1>(qrl) + get <2>(qrl) - 1)))
return true;
else return false;
}
signed main() {
int n = read();
tupl qrl;
get <0>(qrl) = read(), get <1>(qrl) = read(), get <2>(qrl) = read();
f[0][0] = 1;
int k = get <0>(qrl) + get <1>(qrl) + get <2>(qrl);
for (int i = 1; i <= n; i++)
for (int T = 0; T < 1 << k; T++)
for (int j = 1, tp; j <= 10; j++)
if (check(tp = ((T << j) | (1 << (j - 1))) & ((1 << k) - 1), qrl))
f[i][tp] += f[i - 1][T], Mod(f[i][tp]);
int ans = pow_(10, n, mod);
for (int T = 0; T < 1 << k; T++)
ans -= f[n][T], Mod(ans);
write(ans), puts("");
return 0;
}