1327E Count The Blocks(組合數學)

1327E Count The Blocks(組合數學)

題面

題意: 對於一個數字串 xx,可以看做是由多個連續相同的數字塊組成的,比如 x=00027734000x = 00027734000,其長度爲 33 的數字塊有兩個(000000000000),長度爲 22 的數字塊有一個(7777),長度爲 11 的數字塊有 33 個(223344)。現在給整數 nn,表示有 0010n110^n-110n10^n 個數字,現在要求這些數字中長度爲 i[1,n]i \le [1, n] 的數字塊的個數,答案對 998244353998244353​ 取模。

範圍1n2e51 \le n \le 2e5

分析:直接枚舉所有的數字進行統計肯定是不行的,根據數據範圍應該需要對每種長度的數字塊,通過公式計算出其數量。

因爲數字塊是連續相同的數字,因此可以直接看做是一個點。比如當前 n=4i=4n = 4,i = 4,相當於 n=1,i=1n = 1, i = 1,總方案數爲 10100,1,2,3...90,1,2,3...9),對應 (0000,1111,2222,...99990000,1111,2222,...9999)。若當前 n=4,i=2n = 4, i = 2,相當於 n=3,i=1n = 3, i = 1…因此這些問題都可以轉換成 n=x,i=1n = x, i = 1 的情況。

那麼我們只要求當 n=x,i=1n = x,i = 1 的答案。

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

① 這個點在第一位,那麼方案數爲 109101010*9*10*10

② 這個點在第二位,那麼方案數爲 10991010*9*9*10

③ 這個點在第三位,那麼方案數爲 10991010*9*9*10​

④ 這個點在第四位,那麼方案數爲 109101010*9*10*10

我們可以發現除了兩端的點,中間位置的方案數都相同,可以只計算一次。

對於中間位置的點,該點的數字方案有 1010 種,與之相鄰的兩個點方案數爲 99,其餘點的方案數爲 1010,故方案數爲 109910n3=8110n210*9*9*10^{n-3} = 81*10^{n-2},而中間位置的點有 n2n-2 個,所以中間所有位置的總方案爲 (n2)8110n2(n-2)*81*10^{n-2}

對於兩端的點,該點的數字方案有 1010 種,與之相鄰的一個點方案數爲 99,其餘點的方案數爲 1010,故方案數爲 10910n2=910n110*9*10^{n-2} = 9*10^{n-1},有左右兩個端點,所有總方案數爲 1810n118*10^{n-1}

因此,對於所有的長度 ii,我們都可以用上述的公式在 O(1)O(1) 的時間內算出其方案數,總體時間複雜度爲 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】感謝觀看

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章