[BZOJ5298][CQOI2018]交错序列(DP+矩阵乘法)

https://blog.csdn.net/dream_maker_yk/article/details/80377490

斯特林数有时并没有用。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 const int N=210;
 9 int n,a,b,mod,m,k,ans,fac[N],inv[N];
10 
11 struct Mat{
12     int a[N][N];
13     Mat(){ memset(a,0,sizeof(a)); }
14 };
15 
16 Mat operator *(const Mat &a,const Mat &b){
17     Mat c;
18     rep(i,0,m-1) rep(j,0,m-1) if (a.a[i][j])
19         rep(k,0,m-1) if (b.a[j][k]) c.a[i][k]=(c.a[i][k]+1ll*a.a[i][j]*b.a[j][k])%mod;
20     return c;
21 }
22 
23 Mat ksm(const Mat &a,int b){
24     Mat c=a,res;
25     rep(i,0,m-1) res.a[i][i]=1;
26     for (; b; c=c*c,b>>=1)
27         if (b & 1) res=res*c;
28     return res;
29 }
30 
31 int C(int n,int m){ return n<m ? 0 : 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod; }
32 
33 int ksm(int a,int b){
34     int res=1;
35     for (; b; a=1ll*a*a%mod,b>>=1)
36         if (b & 1) res=1ll*res*a%mod;
37     return res;
38 }
39 
40 int main(){
41     scanf("%d%d%d%d",&n,&a,&b,&mod);
42     k=a+b+1; m=2*k;
43     fac[0]=1; rep(i,1,m) fac[i]=1ll*fac[i-1]*i%mod;
44     inv[m]=ksm(fac[m],mod-2);
45     for (int i=m-1; ~i; i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
46     Mat s; rep(i,0,k-1) s.a[i][i+k]=1;
47     rep(i,0,k-1) rep(j,0,i) s.a[j][i]=s.a[j+k][i]=C(i,j);
48     s=ksm(s,n); int x=1,ans=0;
49     rep(i,0,b) ans=(ans+1ll*C(b,i)*x%mod*(s.a[0][a+b-i]+s.a[0][a+b-i+k])%mod*(((b-i)&1)?-1:1))%mod,x=1ll*x*n%mod;
50     printf("%d\n",(ans+mod)%mod);
51     return 0;
52 }

 

posted @ 2019-01-19 10:05  HocRiser  阅读(166)  评论(0编辑  收藏  举报