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你可以將這個數字串分割成若干個...