[题解] HDU7060 Separated Number 思路整理

题目链接

HDU7060 Separated Number

题目大意

给一个 \(n\) 位数,把该数字分成 \(k\) 段,每种方案的贡献为其分割出的段的数字之和。求所有分法的贡献之和(对 \(998244353\) 取模)。

做法

枚举数位,计算每个数位的贡献。

令这个 \(n\) 位数从高到低第 \(i\) 位为 \(a_i\),那么可以枚举 \(a_i\) 属于分割出的哪段数以统计贡献。

\(a_i\) 被分到了 \(a_L\) ~ \(a_R\) 段,此时 \(a_i\) 的贡献为 \(a_i\times10^{R-i}\),考虑一下情况:

  • \(1<L\)\(R<n\) 时,该段左右两边都有其他段,所以相当于余下的 \(n-(R-L+1)\) 位中插入了一块隔板,方案数为 \(\sum_{j=1}^{k-2}\binom{n-(R-L+1)-1-1}{j-1}=\sum_{j=0}^{k-3}\binom{n-(R-L+1)-2}{j}\)
  • \(L=1\)\(R=n\) 时,没有剩下的数,方案数为 \(1\)
  • \(L=1\)\(R=n\) 时(\(L\)\(R\) 不同时等于 \(n\)),那么只有一边有段,方案即为 \(\sum_{j=1}^{k-1}\binom{n-(R-L+1)-1}{j-1}=\sum_{j=0}^{k-2}\binom{n-(R-L+1)-1}{j}\)

加起来即为答案。

\(ans_1=\sum_{L=2}^{n-1}\sum_{R=L}^{n-1}\left(\sum_{i=L}^Ra_i\times10^{R-i}\right)\times\left(\sum_{j=0}^{k-3}\binom{n-(R-L+1)-2}{j}\right) (L>1\land R<n)\)

\(ans_2=\sum_{i=1}^n a_i\times10^{n-i} (L=1 \land R=n)\)

\(ans_3=\sum_{R=1}^{n-1}\left(\sum_{i=1}^Ra_i10^{R-i}\right)\times\left(\sum_{j=0}^{k-2}\binom{n-R-1}{j}\right) (L=1 \land R<n)\)

\(ans_4=\sum_{L=2}^n\left(\sum_{i=L}^na_i10^{n-i}\right)\times\left(\sum_{j=0}^{k-2}\binom{L-2}{j}\right) (L>1\land R=n)\)

\(ans=ans_1+ans_2+ans_3+ans_4\)

不妨设:

\(f(n)=\sum_{i=1}^n a_i10^{-i}\)

\(g(n)=\sum_{i=1}^n 10^if(i)\)

\(h(n,m)=\sum_{i=0}^m\binom{n}{i}\)

那么:


\(ans_1\)

\(=\sum_{L=2}^{n-1}\sum_{R=L}^{n-1}\left(\sum_{i=L}^Ra_i10^{R-i}\right)\times\left(\sum_{j=0}^{k-3}\binom{n-(R-L+1)-2}{j}\right)\)

\(=\sum_{len=1}^{n-2}\sum_{R=len+1}^{n-1}\left(\sum_{i=R-len+1}^Ra_i10^{R-i}\right)\times\left(\sum_{j=0}^{k-3}\binom{n-len-2}{j}\right)\)

\(=\sum_{len=1}^{n-2}h(n-len-2,k-3)\sum_{R=len+1}^{n-1}\left(\sum_{i=R-len+1}^Ra_i10^{R-i}\right)\)

\(=\sum_{len=1}^{n-2}h(n-len-2,k-3)\sum_{R=len+1}^{n-1}10^R\left(\sum_{i=R-len+1}^Ra_i10^{-i}\right)\)

\(=\sum_{len=1}^{n-2}h(n-len-2,k-3)\sum_{R=len+1}^{n-1}10^R(f(R)-f(R-len))\)

\(=\sum_{len=1}^{n-2}h(n-len-2,k-3)\left[\left(\sum_{R=len+1}^{n-1}10^Rf(R)\right)-\left(\sum_{R=len+1}^{n-1}10^Rf(R-len)\right)\right]\)

\(=\sum_{len=1}^{n-2}h(n-len-2,k-3)\left[\left(\sum_{R=len+1}^{n-1}10^Rf(R)\right)-10^{len}\left(\sum_{R=len+1}^{n-1}10^{R-len}f(R-len)\right)\right]\)

\(=\sum_{len=1}^{n-2}h(n-len-2,k-3)\left[g(n-1)-g(len)-10^{len}g(n-1-len)\right]\)


\(ans_2\)

\(=\sum_{i=1}^n a_i10^{n-i}=10^n\sum_{i=1}^na_i10^{-i}=10^nf(n)\)


\(ans_3\)

\(=\sum_{R=1}^{n-1}\left(\sum_{i=1}^Ra_i10^{R-i}\right)\times\left(\sum_{j=0}^{k-2}\binom{n-R-1}{j}\right)\)

\(=\sum_{R=1}^{n-1}10^R\left(\sum_{i=1}^Ra_i10^{-i}\right)\times h(n-R-1,k-2)\)

\(=\sum_{R=1}^{n-1}10^Rf(R)\times h(n-R-1,k-2)\)


\(ans_4\)

\(=\sum_{L=2}^n\left(\sum_{i=L}^na_i10^{n-i}\right)\times\left(\sum_{j=0}^{k-2}\binom{L-2}{j}\right)\)

\(=\sum_{L=2}^n10^n\left(\sum_{i=L}^na_i10^{-i}\right)\times h(L-2,k-2)\)

\(=\sum_{L=2}^n10^n(f(n)-f(L-1))\times h(L-2,k-2)\)


不难求出 \(f(x)\)\(g(x)\),如何求 \(h(n,m)\) 呢?

由定义可以发现 \(h(n,m)\) 表示的是 \(n\) 个位置选不超过 \(m\) 个位置的方案数,考虑使用容斥,从 \(h(n-1,m)\) 得到 \(h(n,m)\)

  • \(h(n,m)\)\(1\) ~ \(n-1\) 选不超过 \(m\) 个位置的方案数,也是 \(2\) ~ \(n\) 选不超过 \(m\) 个位置的方案数。
  • 两区间相加,重叠部分为 \(1\)\(n\) 位置都不选,\(2\) ~ \(n-1\) 选不超过 \(m\) 个位置的方案数,即 \(\sum_{i=0}^m\binom{n-2}{i}\)
  • 缺少部分为 \(1\)\(n\) 位置都选,\(2\) ~ \(n-1\) 选不超过 \(m-2\) 个位置的方案数,即 \(\sum_{i=0}^{m-2}\binom{n-2}{i}\)

可得:

\(h(n,m)\)

\(=2\times h(n-1,m)-\sum_{i=0}^m\binom{n-2}{i}+\sum_{i=0}^{m-2}\binom{n-2}{i}\)

\(=2\times h(n-1,m)-\binom{n-2}{m-1}-\binom{n-2}{m}\)

\(=2\times h(n-1,m)-\binom{n-1}{m}\)

注意到答案式中仅含 \(h(w,k-2)\)\(h(w,k-3)\),那么可以分别 \(O(n)\) 求出。

\(f(n)\)\(g(n)\) 也可 \(O(n)\) 处理,再 \(O(n)\) 计算答案,故总复杂度 \(O(n)\)

代码

const ll mod = 998244353;
const int N = 1000010, M = 1000000;
int t, n, k, a[N];
char c[N];
ll inv[N], fac[N], finv[N], ten[N], f[N], g[N], h1[N], h2[N];
inline ll C(ll n, ll m) {
	if (m > n) return 0;
	if (m == n || n == 0) return 1;
	return fac[n] * finv[m] % mod * finv[n - m] % mod;
}
inline ll calc() {
	ll res = ten[n] * f[n] % mod;
	if (k == 1) return res;
	for (int R = 1; R <= n - 1; R++) 
		res = (res + ten[R] * f[R] % mod * h1[n - R - 1] % mod) % mod;
	for (int L = 2; L <= n; L++) 
		res = (res + ten[n] * ((f[n] + mod - f[L - 1]) % mod) % mod * h1[L - 2]) % mod;
	if (k == 2) return res;
	for (int len = 1; len <= n - 2; len++)
		res = (res + h2[n - len - 2] * (((g[n - 1] + mod - g[len]) % mod + mod - ten[len] * g[n - 1 - len] % mod) % mod) % mod) % mod;
	return res;
}
int main() {
	fac[0] = fac[1] = 1;
	for (int i = 2; i <= M; i++) fac[i] = fac[i - 1] * i % mod;
	inv[1] = 1;
	for (int i = 2; i <= M; i++) inv[i] = (mod - (mod / i) * inv[mod % i]) % mod;
	finv[0] = finv[1] = 1;
	for (int i = 2; i <= M; i++) finv[i] = finv[i - 1] * inv[i] % mod;
	ten[0] = 1;
	for (int i = 1; i <= M; i++) ten[i] = ten[i - 1] * 10 % mod;	

	t = read();
	while (t--) {
		k = read();
		scanf("%s", c + 1);
		n = strlen(c + 1);
		for (int i = 1; i <= n; i++) a[i] = c[i] ^ 48;
		
		for (int i = 1; i <= n; i++) h1[i] = h2[i] = 0;
		ll iv10 = inv[10];
		for (int i = 1; i <= n; i++) {
			f[i] = (f[i - 1] + iv10 * a[i] % mod) % mod;
			iv10 = iv10 * inv[10] % mod;
		}
		for (int i = 1; i <= n; i++) g[i] = (g[i - 1] + f[i] * ten[i] % mod) % mod;
		h1[0] = h2[0] = 1;
		if (k >= 2)
			for (int i = 1; i <= n; i++) h1[i] = ((h1[i - 1] << 1) % mod + mod - C(i - 1, k - 2)) % mod;
		if (k >= 3)
			for (int i = 1; i <= n; i++) h2[i] = ((h2[i - 1] << 1) % mod + mod - C(i - 1, k - 3)) % mod;
		
		printf("%lld\n", calc());
	}
	return 0;
}

参考资料

[组合数学] HDU 7060 Separated Number - AE酱

posted @ 2022-11-03 13:33  shiranui  阅读(42)  评论(0编辑  收藏  举报
*/