[bzoj4870][Shoi2017]组合数问题

来自FallDream的博客,未经允许,请勿转载,谢谢。


与sdoi2017那道题神似

用f[i]表示选出的数量膜k等于i的方案数,容易构造转移矩阵,复杂度k^3log(nk)

也可以构造一个生成函数 复杂度k^2log(nk) 

理论上可以优化到klognlogk 但常数巨大。

#include<iostream>
#include<cstdio>
#define MN 50
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

int n,p,k,r,A[MN+5],B[MN+5],C[MN+5];

void Mul(int*a,int*b)
{
    for(int i=0;i<k;++i) if(a[i])
        for(int j=0;j<k;++j)
            C[(i+j)%k]=(C[(i+j)%k]+1LL*a[i]*b[j])%p; 
    for(int i=0;i<k;++i) a[i]=C[i],C[i]=0;
}

int main()
{
    n=read();p=read();k=read();r=read();
    A[0]=1;B[0]=1;++B[1%k];
    for(long long K=1LL*n*k;K;K>>=1,Mul(B,B))
        if(K&1) Mul(A,B); 
    printf("%d\n",A[r]);
    return 0;
}
posted @ 2017-05-22 21:31  FallDream  阅读(250)  评论(0编辑  收藏  举报