[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;
}
posted @ 2024-01-18 15:58  cxqghzj  阅读(8)  评论(0编辑  收藏  举报