• P5343 【XR-1】分块(dp矩阵加速)


    (大意是用数组a里的数字,组成一个序列,使得序列和为n的方案种数)传送门

    (先考虑dp.)

    (但是不能直接用背包转移,因为是序列,要考虑顺序。)

    (所以,为了去重,我们令dp[i][j]为凑成i最后用的a[j]的方案数)

    dp[0]=1;//把第二维优化掉
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
        if(i>=a[j])
            dp[i]+=dp[i-a[j]];
    

    (接下来考虑用矩阵加速。)

    (设a数组中最大的数是size,那么dp[i]最多从dp[i-size]转移过来,所以矩阵大小是size*size)

    现在我们想用

    [left[ egin{matrix} dp_{size-1}\ dp_{size-2}\ dp_{size-3}\ ....\ 1\ 0\ end{matrix} ight] 得到 left[ egin{matrix} dp_{size}\ dp_{size-1}\ dp_{size-2}\ ....\ 1\ 0\ end{matrix} ight] ]

    那我们的构造矩阵是怎样的呢?

    (第一行因为dp[i]可以从每一个i-a[j]得到,所以所有mat[1][a[j]]=1;)

    (其余行,只需要把mat[i][i-1]设置成1即可(下面的构造矩阵省略了第一行,因为是根据具体数据填写))

    [left[ egin{matrix} dp_{size-1}\ dp_{size-2}\ dp_{size-3}\ ....\ 1\ 0\ end{matrix} ight] * left[ egin{matrix} 0&1&0&0&...&0\ 0&0&1&0&...&0\ 0&0&0&1&...&0\ 0&0&0&0&...&1\ end{matrix} ight] = left[ egin{matrix} dp_{size}\ dp_{size-1}\ dp_{size-2}\ ....\ 1\ 0\ end{matrix} ight] ]

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=1e9+7;
    ll n,pr,x,nf,a[109],dp[109],size,b[109],c[109];
    struct rce{
    	ll m[102][102];
    	rce(){memset(m,0,sizeof(m));}
    };
    rce operator * (rce a,rce b)
    {
    	rce c;
    	for(int i=1;i<=size;i++)
    	for(int j=1;j<=size;j++)
    	{
    		c.m[i][j]=0;
    		for(int k=1;k<=size;k++)
    			c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j]%mod)%mod;
    	}
    	return c;
    }
    rce quickpow(rce a,ll n)
    {
    	rce ans;
    	for(int i=1;i<=size;i++)
    	for(int j=1;j<=size;j++)
    	if(i==j)	ans.m[i][j]=1;
    	else	ans.m[i][j]=0;
    	while(n)
    	{
    		if(n&1)	ans=ans*a;
    		a=a*a;
    		n>>=1;
    	}
    	return ans;
    }
    int main()
    {
    	cin>>n;
    	cin>>pr;
    	for(int i=1;i<=pr;i++)
    	{
    		cin>>x;
    		a[x]=1;
    	}
    	cin>>nf;
    	for(int i=1;i<=nf;i++)
    	{
    		cin>>x;
    		c[x]=1;
    	}
    	for(ll i=1;i<=100;i++)
    	{
    		if(a[i]&&c[i])
    		{
    			b[++b[0]]=i;
    			size=max(size,i);
    		}
    	}
    	dp[0]=1;
    	for(int i=1;i<=size;i++)
    	for(int j=1;j<=b[0];j++)
    	{
    		if(i>=b[j])
    			dp[i]=(dp[i]+dp[i-b[j]])%mod;
    	}
    	rce zao,init;
    	for(int i=1;i<=size;i++)	init.m[i][1]=dp[size-i];
    	for(int i=1;i<=b[0];i++)	zao.m[1][b[i]]=1;
    	for(int i=2;i<=size;i++)	zao.m[i][i-1]=1;
    	zao=quickpow(zao,n-size+1)*init;
    	cout<<zao.m[1][1]%mod;
    }
    
  • 相关阅读:
    安装SQLserver2008时出现的错误
    第二章 语法陷阱
    分享:APK高级保护方法解析(三)
    设计模式_命令模式
    POJ-3134-Power Calculus(迭代加深DFS)
    Rational Rose2007具体安装步骤
    webAPP开发的问题(总结)
    基于Linux的智能家居的设计(5)
    获取表数据的插入SQL
    POJ 3667 Hotel(线段树)
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12694512.html
Copyright © 2020-2023  润新知