[BZOJ 4870][SHOI&SXOI2017]组合数问题(Dp+矩阵优化)

Description

Solution

其实看到数据范围应该往矩阵乘法这边想的

考虑式子的实际意义 从n*k个里面选模k等于r个的方案数 Dp

f[i][j]=f[i-1][j]+f[i-1][(j-1+k)%k]

另外给矩阵赋值的时候建议  m.a[(i-1+K)%K][i]++; m.a[i][i]++; 而不是  m.a[(i-1+K)%K][i]=1; m.a[i][i]=1; 

因为K=1的时候会出现偏差…a[0][0]应该为2

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
typedef long long LL;
LL n,r,K,p;
struct Matrix
{
    LL a[51][51];
    Matrix(){memset(a,0,sizeof(a));}
    Matrix operator *(const Matrix& x)
    {
        Matrix ans;
        for(int i=0;i<K;i++)
        {
            for(int j=0;j<K;j++)
            {
                for(int k=0;k<K;k++)
                {
                    ans.a[i][j]+=(a[i][k]*x.a[k][j])%p;
                    ans.a[i][j]%=p;
                }
            }
        }
        return ans;
    }
}m;
Matrix pow(Matrix a,LL n)
{
    Matrix res;
    for(int i=0;i<K;i++)res.a[i][i]=1;
    while(n)
    {
        if(n&1)res=res*a;
        a=a*a;
        n>>=1;
    }
    return res;
}
int main()
{
    scanf("%lld%lld%lld%lld",&n,&p,&K,&r);
    for(int i=0;i<K;i++)
    {
        m.a[(i-1+K)%K][i]++;
        m.a[i][i]++;
    }
    Matrix res=pow(m,1LL*n*K);
    printf("%lld\n",res.a[0][r]);
    return 0;
} 
posted @ 2017-05-02 14:50  Zars19  阅读(582)  评论(0编辑  收藏  举报