bzoj 4870: [Shoi2017]組合數問題 動態規劃
阿新 • • 發佈:2019-01-28
題意
1 ≤ n ≤ 10^9, 0 ≤ r < k ≤ 50, 2 ≤ p ≤ 2^30 − 1
分析
拿到題目就開始狂推式子,看了題解才發現原來是dp。
我們從直觀上來理解我們要求的這個詭異的式子。
實際上就是要我們從
顯然的dp方程
那麼顯然有
矩陣乘法優化即可。
複雜度
還有一種更棒的做法,同樣是dp,但可以發現
可以理解成列舉前n個物品的選法和後n個物品的選法。
那麼直接對dp陣列做快速冪即可。
複雜度 (k2logn)
程式碼
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=55;
LL n,p,k,r;
struct arr{LL f[N];}ans,a;
void mul(arr &a,arr b,arr c)
{
memset(a.f,0,sizeof(a.f));
for (int i=0;i<k;i++)
for (int j=0;j<k;j++)
a.f[(i+j)%k]=(a.f[(i+j)%k]+b.f[i]*c.f[j]%p)%p;
}
void ksm(arr x,LL y)
{
y--;
while (y)
{
if (y&1) mul(ans,ans,x);
mul(x,x,x);y>>=1;
}
}
int main()
{
scanf("%lld%lld%lld%lld",&n,&p,&k,&r);
a.f[0 ]++;a.f[1%k]++;ans=a;
ksm(a,n*k);
printf("%lld",ans.f[r]);
return 0;
}