P5343 【XR-1】分块-矩阵快速幂加速DP

此类问题​​​​​​的一般套路(详解)矩阵快速幂详解与常见转移矩阵的构造_石油生产队里的秦三的博客-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;


}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qinsanma and Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值