题解
很容易可以得到一个方程,
f
(
i
)
=
∑
j
=
1
t
f
(
i
−
a
(
j
)
)
f(i)=\sum_{j=1}^t f(i-a(j))
f(i)=∑j=1tf(i−a(j))(
a
a
a 数组记录两个人都允许的长度
)。然后发现
a
(
j
)
a(j)
a(j) 很小,所以将转移方程写成矩阵之后就可以用矩阵快速幂优化啦(设
a
m
a
x
amax
amax 为
a
a
a 数组中最大的数):
[
f
(
n
−
1
)
f
(
n
−
2
)
⋮
f
(
n
−
a
m
a
x
+
1
)
f
(
n
−
a
m
a
x
)
]
×
[
第
一
行
根
据
a
数
组
而
定
1
0
0
⋯
0
0
(
这
是
第
二
行
)
0
1
0
⋯
0
0
0
0
1
⋯
0
0
⋮
⋱
0
0
0
⋯
1
0
]
=
[
f
(
n
)
f
(
n
−
1
)
⋮
f
(
n
−
a
m
a
x
+
2
)
f
(
n
−
a
m
a
x
+
1
)
]
\left[ \begin{array}{c} f(n-1)\\ f(n-2)\\ \vdots\\ f(n-amax+1)\\ f(n-amax) \end{array} \right]\times \\ \left[ \begin{array}{c} 第&一&行&根&据&a&数组而定\\ 1 & 0 & 0 &\cdots& 0 & 0 & (这是第二行)\\ 0 & 1 & 0 &\cdots& 0 & 0\\ 0 & 0 & 1 &\cdots& 0 & 0\\ \vdots & \ddots\\ 0 & 0 & 0 &\cdots& 1 & 0\\ \end{array} \right]=\\ \left[ \begin{array}{c} f(n)\\ f(n-1)\\ \vdots\\ f(n-amax+2)\\ f(n-amax+1) \end{array} \right]
⎣⎢⎢⎢⎢⎢⎡f(n−1)f(n−2)⋮f(n−amax+1)f(n−amax)⎦⎥⎥⎥⎥⎥⎤×⎣⎢⎢⎢⎢⎢⎢⎢⎡第100⋮0一010⋱0行0010根⋯⋯⋯⋯据0001a0000数组而定(这是第二行)⎦⎥⎥⎥⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎢⎡f(n)f(n−1)⋮f(n−amax+2)f(n−amax+1)⎦⎥⎥⎥⎥⎥⎤
于是代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define mod 1000000007ll
struct matrix{
int w,h;//宽,高
ll a[210][210];
matrix()
{
w=h=0;
memset(a,0,sizeof(a));
}
matrix operator *(matrix &x)
{
matrix re;re.h=h;re.w=x.w;
for(int i=1;i<=re.h;i++)
for(int j=1;j<=re.w;j++)
for(int k=1;k<=w;k++)
re.a[i][j]+=a[i][k]*x.a[k][j],re.a[i][j]%=mod;
return re;
}
void print()
{
for(int i=1;i<=h;i++)
{
for(int j=1;j<=w;j++)
printf("%lld ",a[i][j]);
printf("\n");
}
}
};
matrix b,c;
ll n,f[210];
int m,a[210],t=0;
bool v[210];
int main()
{
scanf("%lld",&n);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
v[x]=true;
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
if(v[x])a[++t]=x,v[x]=false;//找出重复的
}
sort(a+1,a+t+1);
f[0]=1;
b.w=1;b.h=a[t];
for(int i=1;i<=b.h;i++)
for(int j=1;j<=t&&i>=a[j];j++)
f[i]=(f[i]+f[i-a[j]])%mod;//先暴力求出前b.h项
for(int i=b.h;i>=1;i--)
b.a[i][1]=f[b.h-i+1];
c.h=c.w=a[t];
for(int i=1;i<=t;i++)
c.a[1][a[i]]=1;
for(int i=2;i<=c.h;i++)
c.a[i][i-1]=1;
if(n<=a[t])printf("%lld",f[n]);
else//矩阵快速幂
{
n-=a[t];
matrix ans;ans.w=-1;
while(n>0)
{
if(n%2==1)
{
if(ans.w==-1)ans=c;
else ans=ans*c;
}
c=c*c;
n/=2;
}
ans=ans*b;
printf("%lld",ans.a[1][1]);
}
}