题解 P5343 【【XR-1】分块】

· · 题解

首先搞出能用的块大小集合S

然后令f_n表示长度为n的序列有几种分块方案。

由于块大小最大只有$100$,这是个线性递推的形式。 所以我们可以用矩阵快速幂对其进行加速。 最初始$100$个状态可以直接递推处理出来。 时间复杂度$O(100^3\log n)$。 ## Code: ```cpp #pragma GCC optimize("Ofast") #pragma GCC optimize("unroll-loops") #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") #include<cstdio> #include<cstring> #include<algorithm> const int md=1e9+7; typedef long long LL; int b[105]; inline void upd(int&a){a+=a>>31&md;} struct mat{ int a[100][100]; inline void operator*=(const mat&b){ int c[100][100]; memset(c,0,sizeof c); for(int i=0;i<100;++i) for(int j=0;j<100;++j){ int&tmp=c[i][j]; for(int k=0;k<100;k+=4) tmp=(tmp+(LL)a[i][k]*b.a[k][j]+(LL)a[i][k+1]*b.a[k+1][j]+(LL)a[i][k+2]*b.a[k+2][j]+(LL)a[i][k+3]*b.a[k+3][j])%md; } memcpy(a,c,sizeof a); } }a,c; LL n; int na,nb,dp[105]; inline void pow(mat a,LL b,mat&ret){ for(;b;b>>=1,a*=a)if(b&1)ret*=a; } int main(){ scanf("%lld%d",&n,&na); for(int x;na--;){ scanf("%d",&x); b[x]=1; } scanf("%d",&nb); for(int x;nb--;){ scanf("%d",&x); if(b[x])a.a[100-x][99]=1; } for(int i=1;i<100;++i)a.a[i][i-1]=1; dp[0]=1; for(int i=1;i<=100;++i) for(int j=1;j<=i;++j) if(a.a[100-j][99])upd(dp[i]+=dp[i-j]-md); for(int i=0;i<100;++i)c.a[0][i]=dp[i]; pow(a,n,c); printf("%d\n",c.a[0][0]); return 0; } ```