1. 程式人生 > 實用技巧 >【六省聯考2017】組合數問題 題解(矩陣快速冪優化DP)

【六省聯考2017】組合數問題 題解(矩陣快速冪優化DP)

題目連結

題目大意:求$(\sum\limits_{i=0}^n C_{nk}^{ik+r})\ mod \ p$的值。

---------------------

講真,一開始看到這個題我都沒往DP方面想,以為是什麼大力推式子的數學題。

設$f_{i,j}$表示考慮前$i$個物品,選出的物品$mod \ k=j$的方案數。最後輸出$f_{n,r}$。

易得轉移方程:

$f_{i,j}=f_{i-1,j}+f_{i-1,j-1}$

$f_{i,0}=f_{i-1,0}+f_{i-1,k-1}$

看到資料範圍想到矩陣加速,有轉移矩陣:

$\begin{bmatrix}1&0&\cdots&0&1\\1&1&0&\cdots&0\\0&1&1&\cdots&0\\\vdots&\ddots&\ddots&\ddots&\vdots\\0&0&\cdots&1&1 \end{bmatrix}$

矩陣快速冪乘$nk$次方即可。

注意當$k=1$時只有一個元素,其初始值為2。

程式碼:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,p,k,r;
struct node
{
    int a[55][55];
    node(){
        memset(a,0,sizeof(a));
    }
    inline void build(){
        for (int i=1;i<=k;i++) a[i][i]=1;
    }
};
node operator
* (const node x,const node y) { node z; for (int l=1;l<=k;l++) for (int i=1;i<=k;i++) for (int j=1;j<=k;j++) z.a[i][j]=(z.a[i][j]+x.a[i][l]*y.a[l][j])%p; return z; } signed main() { cin>>n>>p>>k>>r;int mi=n*k; node a,ans;ans.build();
for (int i=1;i<=k-1;i++) a.a[i][i]++,a.a[i][i+1]++; a.a[k][1]++,a.a[k][k]++; while(mi) { if (mi&1) ans=ans*a; a=a*a; mi>>=1; } printf("%lld",ans.a[k][k-r]); return 0; }