[CQOI2018] 交错序列(矩阵加速优化dp)
problem
luogu-P4456
solution
預處理階乘和階乘的逆元,枚舉 111 出現次數 iii,∑(n?i+1i)(n?i)aib\sum\binom{n-i+1}{i}(n-i)^ai^b∑(in?i+1?)(n?i)aib。
-
(n?i+1i)\binom{n-i+1}{i}(in?i+1?) 如何推出來?
從 nnn 個中選 iii 個 (ni)\binom ni(in?)。容斥不太可能。
隔板法。分成 iii 堆需要插 i?1i-1i?1 塊板。
考慮 111 不能連續也就是說兩塊板之間至少要隔兩個盒子。
隔板法經典強制每個至少有 111 個的方法類比過來。
發現只需要拿走 i?1i-1i?1 個盒子,剩下的選的位置就可以相鄰。
但這樣是不行的,快速冪部分耗時大,且 n,mn,mn,m 之間大小關系不定,逆元可能不存在,無法預處理。
考慮解決組合數計算部分。
-
用 lucas\text{lucas}lucas 定理算。
不能在要求時間內通過。
-
算一個組合數,可以將分子分母質因數分解,然后在指數位置進行加減運算。最后在把所有質因數乘起來,就可以巧妙避免計算逆元的問題。
但本題組合數要求計算多個,時間開銷依然未能縮減。
考慮解決快速冪計算部分。
-
xa,ybx^a,y^bxa,yb 都是完全積性函數。
f(i)=ia?f(xy)=(xy)a=f(x)f(y)=xayaf(i)=i^a\Rightarrow f(xy)=(xy)^a=f(x)f(y)=x^ay^af(i)=ia?f(xy)=(xy)a=f(x)f(y)=xaya。
所以可以 O(n)O(n)O(n) 線性篩。
這是解決冪運算指數固定的常見方法。
這種做法是不能通過本題的,洛谷題解有一篇能過完全是數據問題。這里只是想記錄一些 trick\text{trick}trick。
考慮計算貢獻 xayb=(n?y)ayb=∑i=0a(ai)ni(?1)a?iya?iybx^ay^b=(n-y)^ay^b=\sum_{i=0}^a\binom ain^i(-1)^{a-i}y^{a-i}y^bxayb=(n?y)ayb=∑i=0a?(ia?)ni(?1)a?iya?iyb。
發現當枚舉 iii 時 (ai)ni(?1)a?i\binom{a}{i}n^i(-1)^{a-i}(ia?)ni(?1)a?i 均為常數,唯一隨序列不同而變化的是 ya+b?iy^{a+b-i}ya+b?i,準確來說應該是 yyy。
我們可以計算所有序列中 111 的個數的 a+b?ia+b-ia+b?i 次方之和,然后就可以計入答案。
設 f(i,j,k):f(i,j,k):f(i,j,k): 考慮前 iii 位,第 iii 位為 k∈[0,1]k\in[0,1]k∈[0,1],所有合法序列的 111 的個數的 jjj 次方之和,即 ∑yj\sum y^j∑yj。
-
iii 填 000,則對前面無限制。沒有新增的 111 的個數,貢獻不變。
f(i,j,0)=f(i?1,j,0)+f(i?1,j,1)f(i,j,0)=f(i-1,j,0)+f(i-1,j,1)f(i,j,0)=f(i?1,j,0)+f(i?1,j,1)。
-
iii 填 111,則前一位不能為 111,只能從 000 轉移。
此時將有 yj→(y+1)jy^j\rightarrow (y+1)^jyj→(y+1)j 直接二項式展開。
(y+1)j=∑k=0j(jk)yk1j?k(y+1)^j=\sum_{k=0}^j\binom jky^k1^{j-k}(y+1)j=∑k=0j?(kj?)yk1j?k。
所有序列的 yky^kyk 之和恰恰是 f(,k,)f(,k,)f(,k,) 的定義。
所以轉移為:f(i,j,1)=∑k=0j(jk)f(i?1,k,0)f(i,j,1)=\sum_{k=0}^j\binom jkf(i-1,k,0)f(i,j,1)=∑k=0j?(kj?)f(i?1,k,0)。
發現轉移壓根和 iii 這一維沒有關系,所以是可以矩陣加速 nnn 的。
注意我們要計算到 ya+by^{a+b}ya+b 次方,且我們將兩種轉移合并在一起。
構造初始矩陣 f:[f0,0,f1,0,...,fa+b,0,f0,1,f1,1,...,fa+b,1]f:[f_{0,0},f_{1,0},...,f_{a+b,0},f_{0,1},f_{1,1},...,f_{a+b,1}]f:[f0,0?,f1,0?,...,fa+b,0?,f0,1?,f1,1?,...,fa+b,1?]。形式化為 [fj,0∣fj,1],j∈[0,a+b][f_{j,0}\mid f_{j,1}],j\in[0,a+b][fj,0?∣fj,1?],j∈[0,a+b]。
構造加速矩陣 ggg:分拆為四個部分。
- 左上角為單位矩陣。表示 f(,0)→f′(,0)f(,0)\rightarrow f'(,0)f(,0)→f′(,0)。
- 左下角為單位矩陣。表示 f(,1)→f′(,0)f(,1)\rightarrow f'(,0)f(,1)→f′(,0)。
- 右上角為組合數矩陣。注意是行列交換了的,表示 f(,0)→f′(,1)f(,0)\rightarrow f'(,1)f(,0)→f′(,1)。
- 右下角為全 000 矩陣。表示不合法 f(,1)→f′(,1)f(,1)\rightarrow f'(,1)f(,1)→f′(,1)。
具體可以自己畫一下,發現是匹配的。
code
#include <bits/stdc++.h> using namespace std; #define int long long #define maxn 185 int n, a, b, mod, m1, m2; int C[maxn][maxn]; struct matrix {int c[maxn][maxn];matrix() { memset( c, 0, sizeof( c ) ); }matrix operator * ( matrix &v ) {matrix ans;for( int i = 0;i < m2;i ++ )for( int k = 0;k < m2;k ++ )if( c[i][k] ) //稀疏矩陣經典有效優化for( int j = 0;j < m2;j ++ ) //j,k交換 內存訪問連續 優化常數ans.c[i][j] = (ans.c[i][j] + c[i][k] * v.c[k][j]) % mod;return ans;} }g, f;signed main() {scanf( "%lld %lld %lld %lld", &n, &a, &b, &mod );m1 = a + b + 1, m2 = m1 << 1;for( int i = 0;i <= m1;i ++ ) {C[i][0] = C[i][i] = 1;for( int j = 1;j < i;j ++ )C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;}for( int i = 0;i < m1;i ++ ) {g.c[i][i] = g.c[i + m1][i] = 1;for( int j = i;j < m1;j ++ )g.c[i][j + m1] = C[j][i];}f.c[0][0] = 1; int x = n;while( x ) {if( x & 1 ) f = f * g;g = g * g;x >>= 1;}x = 1; int ans = 0;for( int i = 0;i <= a;i ++, x = x * n % mod )if( (a - i) & 1 )(ans -= (f.c[0][a+b-i] + f.c[0][a+b-i+m1]) % mod * C[a][i] % mod * x) %= mod;else (ans += (f.c[0][a+b-i] + f.c[0][a+b-i+m1]) % mod * C[a][i] % mod * x) %= mod;printf( "%lld\n", (ans + mod) % mod );return 0; } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的[CQOI2018] 交错序列(矩阵加速优化dp)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 王者荣耀各服务器位置,王者荣耀国服兰陵王
- 下一篇: [AtCoder Educational