此类问题的一般套路(详解)矩阵快速幂详解与常见转移矩阵的构造_石油生产队里的秦三的博客-CSDN博客
先求出本次的
再考虑承接
然后特殊到一般
另外在预处理dp100的时候,还是不能按照完全背包求方案数,因为题目还是要去有次序的,而这又对应了快速幂时对于一个fn,需要知道其前面全部ai的情况。
#include<iostream>
#include<cstring>
#include<cstdio>
# define mod 1000000007
using namespace std;
typedef long long int ll;
ll dp[110], c[200],len,temp[110][110];
bool book1[200],book2[200];
void cheng(ll a[][110],ll b[][110])
{
memset(temp,0,sizeof(temp));
for(int i=1;i<=100;i++)
{
for(int j=1;j<=100;j++)
{
for(int k=1;k<=100;k++)
{
temp[i][j]=(temp[i][j]+ a[i][k]*b[k][j])%mod;
}
}
}
for(int i=1;i<=100;i++)
{
for(int j=1;j<=100;j++)
{
a[i][j]=temp[i][j];
}
}
}
ll res[110][110];
ll a[110][110];
void quickpow(int pow)
{
for(int i=1;i<=100;i++)
{
res[i][i]=1;
}
while(pow)
{
if(pow&1)
cheng(res,a);
pow>>=1;
cheng(a,a);
}
}
int main()
{
int n,m,x;
cin>>n;
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>x;
book1[x]=1;
}
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>x;
book2[x]=1;
}
for(int i=1;i<=100;i++)
{
if(book1[i]&&book2[i])
{
len++;
c[len]=i;
}
}
dp[0]=1;
for(int i=1;i<=100;i++)
{
for(int j=1;j<=len;j++)
{
if(i>=c[j])
dp[i]+=dp[i-c[j]];
dp[i]%=mod;
}
}
if(n<=100)
{
cout<<dp[n];
return 0;
}
for(int i=1;i<=len;i++)
{
a[1][c[i]]=1;
}
for(int i=2;i<=100;i++)
{
a[i][i-1]=1;
}
quickpow(n-99);
ll answer=0;
for(int i=99;i>=0;i--)
{
answer=(answer+dp[i]*res[1][100-i])%mod;
}
cout<<answer;
}