4037 HAOI2015 數字串拆分

2021-07-27 02:28:21 字數 1819 閱讀 7957

time limit: 10 sec  

memory limit: 256 mb

submit: 255  

solved: 156 [

submit][

status][

discuss]

你有乙個長度為n的數字串。定義f(s)為將s拆分成若干個1~m的數的和的方案數,比如m=2時,f(4)=5,分別為4=1+

1+1+1你可以將這個數字串分割成若干個數字(允許前導0),將他們加起來,求f,並求和。比如g(123)=f(1+2+3)

+f(1+23)+f(12+3)+f(123)。已知字串和m後求答案對998244353(7×17×223+1,乙個質數)取模後的值。

第一行輸入乙個字串,第二行輸入m

僅輸出乙個數表示答案

1233

394608467

對於100%的資料,字串長度不超過500,m<=5

鳴謝bhiaibogf提供 [

submit][

status][

discuss]

先考慮f(n)的求法,顯然f(n) = f(n-1) + f(n-2) + ... + f(n-m),也就是乙個m階遞推數列,f[0] = 1

這個東西顯然是能用矩陣來維護的,反正寫乙個m * m的轉移矩陣。。。。

不妨記f(n)最終使用的轉移矩陣是h(n)

那麼f(a1 + a2 + ... + ak)使用的轉移矩陣就能寫成h(a1) * h(a2) * ... * h(ak)

通過矩陣乘法滿足結合律推出,這是乙個很不錯的性質

記d[i][j]為原數字串中i ~ j位構成的數字的轉移矩陣,

g[i]為以i結尾之前所有種類轉移矩陣的和,g[i] = ∑g[j] * d[j + 1][i]

因為矩陣乘法也滿足分配率,所以這樣的方程是對的

最後拿g[n]瞎算一下就得出答案了

o(5 * n^2 * m^3),這個常數5是預處理d陣列的時候自帶的。。。可能有更優的吧,反正我是這樣了。。

這樣子複雜度挺大的,所以常數得注意點

#include#include#includeusing namespace std;

const int n = 505;

const int m = 5;

typedef long long ll;

const ll mo = 998244353;

int n,m;

char s[n];

struct data

data operator += (const data &b)

}}d[n][n],mi[10],g[n];

data ksm(data &k)

int main()

}for (int i = 1; i <= n; i++)

for (int j = i - 1; j >= 0; j--)

g[i] += g[j] * d[j + 1][i];

ll ans = 0;

for (int i = 0; i < m; i++) ans += g[n].a[0][i];

cout << ans % mo << endl;

return 0;

}

HAOI2015 bzoj4037 數字串拆分

description 你有乙個長度為n的數字串。定義f s 為將s拆分成若干個1 m的數的和的方案數,比如m 2時,f 4 5,分別為4 1 1 1 1你可以將這個數字串分割成若干個數字 允許前導0 將他們加起來,求f,並求和。比如g 123 f 1 2 3 f 1 23 f 12 3 f 123...

HAOI2015 數字串拆分

你有乙個長度為n的數字串。定義f s 為將s拆分成若干個1 m的數的和的方案數,比如m 2時,f 4 5,分別為4 1 1 1 1你可以將這個數字串分割成若干個數字 允許前導0 將他們加起來,求f,並求和。比如g 123 f 1 2 3 f 1 23 f 12 3 f 123 已知字串和m後求答案對...

HAOI2015 數字串拆分 矩陣乘法

4037 haoi2015 數字串拆分 time limit 10 sec memory limit 256 mb description 你有乙個長度為n的數字串。定義f s 為將s拆分成若干個1 m的數的和的方案數,比如m 2時,f 4 5,分別為4 1 1 1 1你可以將這個數字串分割成若干個...