【Luogu】P3746组合数问题(矩阵)

  题目链接

  哇我一个活人的智商被题目碾压了

  可以把问题转化为有nk个物品,问拿i件物品的方案数有多少种,其中i%k=r。

  然后矩阵乘法加速DP即可。

  

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cctype>
#define maxn 55
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int m;long long mod,n,r;

struct Matrix{
    long long s[maxn][maxn];
    void clear(){memset(s,0,sizeof(s));}
    Matrix operator *(Matrix a){
        Matrix ans;    ans.clear();
        for(int i=1;i<=m;++i)
            for(int j=1;j<=m;++j)
                for(int k=1;k<=m;++k)    ans.s[i][j]=(ans.s[i][j]+s[i][k]*a.s[k][j]%mod)%mod;
        return ans;
    }
}start,d;

Matrix Pow(Matrix a,long long b){
    Matrix ret;    ret.clear();
    for(int i=1;i<=m;++i)    ret.s[i][i]=1;
    while(b){
        if(b&1)    ret=ret*a;
        a=a*a;
        b>>=1;
    }
    return ret;
}

int main(){
    start.clear();
    n=read();mod=read();m=read();r=read();
    //start.s[1][m]=1;
    for(int i=1;i<=m;++i)
        start.s[i][i]++,start.s[(i-2+m)%m+1][i]++;
    n*=m;
    start=Pow(start,n);
    d.s[1][1]=1;
    d=d*start;
    printf("%lld\n",d.s[1][r+1]);
    return 0;
}

 

posted @ 2018-04-12 14:15  Konoset  阅读(183)  评论(0编辑  收藏  举报