1327E Count The Blocks(组合数学)

本文详细解析了1327ECountTheBlocks问题,这是一个关于组合数学的问题,涉及到数字串中连续相同数字块的计数。通过对不同长度的数字块进行分析,提出了一个高效的算法,能够在O(n)的时间复杂度内解决该问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1327E Count The Blocks(组合数学)

题面

题意: 对于一个数字串 x x x,可以看做是由多个连续相同的数字块组成的,比如 x = 00027734000 x = 00027734000 x=00027734000,其长度为 3 3 3 的数字块有两个( 000 000 000 000 000 000),长度为 2 2 2 的数字块有一个( 77 77 77),长度为 1 1 1 的数字块有 3 3 3 个( 2 2 2 3 3 3 4 4 4)。现在给整数 n n n,表示有 0 0 0 1 0 n − 1 10^n-1 10n1 1 0 n 10^n 10n 个数字,现在要求这些数字中长度为 i ≤ [ 1 , n ] i \le [1, n] i[1,n] 的数字块的个数,答案对 998244353 ​ 998244353​ 998244353 取模。

范围 1 ≤ n ≤ 2 e 5 1 \le n \le 2e5 1n2e5

分析:直接枚举所有的数字进行统计肯定是不行的,根据数据范围应该需要对每种长度的数字块,通过公式计算出其数量。

因为数字块是连续相同的数字,因此可以直接看做是一个点。比如当前 n = 4 , i = 4 n = 4,i = 4 n=4i=4,相当于 n = 1 , i = 1 n = 1, i = 1 n=1,i=1,总方案数为 10 10 10 0 , 1 , 2 , 3...9 0,1,2,3...9 0,1,2,3...9),对应 ( 0000 , 1111 , 2222 , . . . 9999 0000,1111,2222,...9999 0000,1111,2222,...9999)。若当前 n = 4 , i = 2 n = 4, i = 2 n=4,i=2,相当于 n = 3 , i = 1 n = 3, i = 1 n=3,i=1…因此这些问题都可以转换成 n = x , i = 1 n = x, i = 1 n=x,i=1 的情况。

那么我们只要求当 n = x , i = 1 n = x,i = 1 n=x,i=1 的答案。

例如 n = 4 , i = 1 ​ n = 4, i = 1​ n=4,i=1

① 这个点在第一位,那么方案数为 10 ∗ 9 ∗ 10 ∗ 10 10*9*10*10 1091010

② 这个点在第二位,那么方案数为 10 ∗ 9 ∗ 9 ∗ 10 10*9*9*10 109910

③ 这个点在第三位,那么方案数为 10 ∗ 9 ∗ 9 ∗ 10 ​ 10*9*9*10​ 109910

④ 这个点在第四位,那么方案数为 10 ∗ 9 ∗ 10 ∗ 10 10*9*10*10 1091010

我们可以发现除了两端的点,中间位置的方案数都相同,可以只计算一次。

对于中间位置的点,该点的数字方案有 10 10 10 种,与之相邻的两个点方案数为 9 9 9,其余点的方案数为 10 10 10,故方案数为 10 ∗ 9 ∗ 9 ∗ 1 0 n − 3 = 81 ∗ 1 0 n − 2 10*9*9*10^{n-3} = 81*10^{n-2} 109910n3=8110n2,而中间位置的点有 n − 2 n-2 n2 个,所以中间所有位置的总方案为 ( n − 2 ) ∗ 81 ∗ 1 0 n − 2 (n-2)*81*10^{n-2} (n2)8110n2

对于两端的点,该点的数字方案有 10 10 10 种,与之相邻的一个点方案数为 9 9 9,其余点的方案数为 10 10 10,故方案数为 10 ∗ 9 ∗ 1 0 n − 2 = 9 ∗ 1 0 n − 1 10*9*10^{n-2} = 9*10^{n-1} 10910n2=910n1,有左右两个端点,所有总方案数为 18 ∗ 1 0 n − 1 18*10^{n-1} 1810n1

因此,对于所有的长度 i i i,我们都可以用上述的公式在 O ( 1 ) O(1) O(1) 的时间内算出其方案数,总体时间复杂度为 O ( n ) ​ O(n)​ O(n)

Code

#include <bits/stdc++.h>
#define int long long
#define double long double
using namespace std;

const int MAXN = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 998244353;
const double eps = 1e-9;
const double PI = acos(-1.0);

int n;

inline int read()
{
    int s = 0, w = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            w = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
        s = s * 10 + ch - '0', ch = getchar();
    return s * w;
}

int num[MAXN];

signed main()
{
    // 预处理一下,也可以不预处理
    num[0] = 1;
    for (int i = 1; i < MAXN; i++)
    {
        num[i] = num[i - 1] % MOD * 10 % MOD;
    }
    n = read();
    for (int i = 1; i <= n; i++)
    {
        if (i > 1)
            cout << " ";
        int len = n - i + 1;  // 区间缩点后总点数
        int ans;
        // 2个点以上套公式
        if (len >= 2)
        {
            ans = (len - 2) % MOD * 81 % MOD * num[len - 2] % MOD + 18 * num[len - 1] % MOD;
        }
        // 1个点只有10种方案数
        else
        {
            ans = 10;
        }
        cout << ans % MOD;
    }
    cout << endl;
    return 0;
}

【END】感谢观看

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值