CodeForces 288E Polo the Penguin and Lucky Numbers

洛谷传送门

CF 传送门

虚高 *2800,放模拟赛 T1 人均切了。

首先我们发现这玩意有可减性,用 \([1, r]\) 的答案减去 \([1, l]\) 即可。所以接下来我们只讨论前缀的情况。

考虑数位 dp。为了计算题目的那玩意我们考虑把每个状态的 dp 值用一个三元组 \((a_1, a_n, \sum\limits_{i = 1}^{n - 1} a_i a_{i + 1})\) 表示。那么这样是可以合并的,\(\sum\limits_{i = 1}^{n - 1} a_i a_{i + 1}\) 变成两边的 \(\sum\limits_{i = 1}^{n - 1} a_i a_{i + 1}\) 之和再加上左边的 \(a_n\) 乘上右边的 \(a_1\) 即可。

但是我们发现我们还要进行让全部 \(a_i\) 加上 \(x = t \times 10^k\) 的操作。考虑 \(\sum\limits_{i = 1}^{n - 1} (x + a_i) (x + a_{i + 1}) = (n - 1)x^2 + x \sum\limits_{i = 1}^{n - 1} (a_i + a_{i + 1}) + \sum\limits_{i = 1}^{n - 1} a_i a_{i + 1}\)。所以我们多维护 \(\sum\limits_{i = 1}^{n - 1} a_i + a_{i + 1}\)\(n\) 即可转移。

时间复杂度 \(O(\log_{10} r)\)

code
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 100100;
const ll mod = 1000000007;

ll a[maxn], b[maxn], n, pw[maxn];
char s[maxn], t[maxn];
bool g[maxn][2];

struct node {
	ll l, r, x, y, z;
	node(ll a = 0, ll b = 0, ll c = 0, ll d = 0, ll e = 0) : l(a), r(b), x(c), y(d), z(e) {}
} f[maxn][2];

inline node operator + (const node &a, const node &b) {
	node res;
	res.l = a.l;
	res.r = b.r;
	res.x = (a.x + b.x + a.r * b.l) % mod;
	res.y = (a.y + b.y + a.r + b.l) % mod;
	res.z = (a.z + b.z) % mod;
	return res;
}

node dfs(int pos, bool lim, ll *a) {
	if (pos > n) {
		return node(0, 0, 0, 0, 1);
	}
	if (g[pos][lim]) {
		return f[pos][lim];
	}
	g[pos][lim] = 1;
	node &ans = f[pos][lim];
	ll up = (lim ? a[pos] : 9);
	for (ll x : {4, 7}) {
		if (x > up) {
			break;
		}
		node res = dfs(pos + 1, lim & (x == up), a);
		ll t = x * pw[n - pos] % mod;
		res.l = (res.l + t) % mod;
		res.r = (res.r + t) % mod;
		res.x = (res.x + t * t % mod * (res.z + mod - 1) + t * res.y) % mod;
		res.y = (res.y + t * 2 % mod * (res.z + mod - 1)) % mod;
		if (x == 4) {
			ans = res;
		} else {
			ans = ans + res;
		}
	}
	return ans;
}

void solve() {
	scanf("%s%s", s + 1, t + 1);
	n = strlen(s + 1);
	pw[0] = 1;
	for (int i = 1; i <= n; ++i) {
		a[i] = s[i] - '0';
		b[i] = t[i] - '0';
		pw[i] = pw[i - 1] * 10 % mod;
	}
	ll ans = dfs(1, 1, b).x;
	mems(g, 0);
	ans = (ans - dfs(1, 1, a).x + mod) % mod;
	printf("%lld\n", ans);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2024-01-24 11:20  zltzlt  阅读(19)  评论(0)    收藏  举报