矩阵快速幂专题(一)

最近闲来无事,准备集中精力刷一波数论与图论。矩阵快速幂是数论里面的重要组成部分,值得我好好学习一下。因为题目比较多,分析也比较多,所以将此专题分成几个部分。做完这一专题,可能会暂时转向图论部分,然后等我组合数学学得差不多了,再回过头来继续做数论题。

矩阵快速幂算法的核心思想是将问题建模转化为数学模型(有一些简单题目是裸的矩阵模型,但是大部分难题就是难在要构造矩阵,用矩阵方法解决问题),推倒递推式,构造计算矩阵,用快速幂的思想求解矩阵A的n次方取mod,从而得到矩阵里面你需要的数据。

矩阵快速幂问题有某些特征,是类似快速幂的形式。首先,从题目中是一定可以得到一个递推式的,而且这个递推式不是简单的An与An-1的关系,而是关系式中带有An-2或之后的项,还有的情况甚至带有常数项和多个数列的组合(加减乘数);其次,数据量比较大,不可能用打表方法做出来;最后,有些题目可能与矩阵一点没有关系,但是通过规律分析,能够转化为已知递推式求解某一项(取模)的。

这里给出模版:  我觉得我的矩阵模版不是特别好,但是也不是特别麻烦,所以请读者自行选择是否采用

<span style="font-size:18px;">#define maxn 10+5;
typedef long long ll;
const ll mod = 1e9+7;
#define clr(x,y) memset(x,y,sizeof(x))
struct matrix
{
	int n;
	ll maze[maxn][maxn];
	void init(int n)
	{
		this->n=n;
		clr(maze,0);
	}
	matrix operator *(const matrix& rhs)
	{
		matrix ans;
		ans.init(n);
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				for(int k=0;k<n;k++)
					ans.maze[i][j]=(ans.maze[i][j]+maze[i][k]*rhs.maze[k][j])%mod;
		return ans;
	}
};
matrix qlow(matrix a,int n)
{
	matrix ans;
	ans.init(a.n);
	for(int i=0;i<a.n;i++)ans.maze[i][i]=1;
	while(n)
	{
		if(n&1)ans=ans*a;
		a=a*a;
		n>>=1;
	}
	return ans;
}</span>

第一题 hdu-1757

分析:题目直接给出了递推式(带有f(x-1)到f(x-10)),而且数据量非常大需要取模(这里并不要管a0~a9的值,若不为01那么只需多考虑一步取模),这是简单的矩阵快速幂裸题。

<span style="font-size:18px;">#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#define maxn 6+5
#define clr(x,y) memset(x,y,sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f;
typedef long long ll;
const double pi = acos( -1 );
//const ll mod = 1e9+7;

int a[10];
ll k,m;
ll qmul(ll a,ll b)
{
     ll ans=0;
    while(b)
    {
        if(b&1)ans=(ans+a)%m;
        a=(a+a)%m;
        b>>=1;
    }
    return ans;
}
struct matrix
{
    int n;
    ll maze[maxn][maxn];
    void init(int n)
    {
        this->n=n;
        clr(maze,0);
    }
    matrix operator * (matrix & rhs)
    {
        matrix ans;
        ans.init(n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                    ans.maze[i][j]=(ans.maze[i][j]+qmul(maze[i][k],rhs.maze[k][j]))%m;
        return ans;
    }
};
matrix qlow(matrix a,ll n)
{
    matrix ans;
    ans.init(a.n);
    for(int i=0;i<ans.n;i++)ans.maze[i][i]=1;
    while(n)
    {
        if(n&1)ans=ans*a;
        a=a*a;
        n>>=1;
    }
    return ans;
}
int main()
{
    //freopen("d:\\acm\\in.in","r",stdin);
    while(~scanf("%lld %lld",&k,&m))
    {
        for(int i=0;i<10;i++)
            scanf("%d",&a[i]);
        if(k<10)
        {
            printf("%lld\n",k%m);
            continue;
        }
        matrix ans;
        ans.init(10);
        for(int i=0;i<10;i++)ans.maze[0][i]=i;
        matrix ant;
        ant.init(10);
        for(int i=0;i<9;i++)ant.maze[i+1][i]=1;
        for(int i=0;i<10;i++)ant.maze[i][9]=a[9-i];
        matrix tmp;
        tmp=qlow(ant,k-9);
        ans=ans*tmp;
        printf("%lld\n",ans.maze[0][9]);
    }
    return 0;
}</span>

第二题 hdu-1575

分析:这道题就是非常直白的矩阵快速幂,将主对角线上的数加起来取模-。-

<span style="font-size:18px;">#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#define maxn 6+5
#define clr(x,y) memset(x,y,sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f;
typedef long long ll;
const double pi = acos( -1 );
const ll mod = 9973;//1e9+7;

ll qmul(ll a,ll b)
{
    ll ans=0;
    while(b)
    {
        if(b&1)ans=(ans+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return ans;
}
struct matrix
{
    int n;
    ll maze[maxn][maxn];
    void init(int n)
    {
        this->n=n;
        clr(maze,0);
    }
    matrix operator * (matrix& rhs)
    {
        matrix ans;
        ans.init(n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                    ans.maze[i][j]=(ans.maze[i][j]+maze[i][k]*rhs.maze[k][j])%mod;
        return ans;
    }
};
matrix qlow(matrix a,int n)
{
    matrix ans;
    ans.init(a.n);
    for(int i=0;i<ans.n;i++)ans.maze[i][i]=1;
    while(n)
    {
        if(n&1)ans=(ans*a);
        a=(a*a);
        n>>=1;
    }
    return ans;
}
int main()
{
    //freopen("d:\\acm\\in.in","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k;
        scanf("%d %d",&n,&k);
        matrix ans;
        ans.init(n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                scanf("%d",&ans.maze[i][j]);
        ans=qlow(ans,k);
        ll anw=0;
        for(int i=0;i<n;i++)
            anw=(anw+ans.maze[i][i])%mod;
        printf("%lld\n",anw);
    }
    return 0;
}</span>

第三题 hdu-2604

分析:我这里只提出我的方法,其他网上大神的方法请到别的博客上查找。

对于L较大的情况(L大于2,至于为什么是2,你没有看见fmf和fff都是三个吗?),我考虑对于在E-queue里面的所有合法队列(-。-,其实和队列没有任何关系)。他们都是以mm,fm,mf,ff之一结尾的,我就分别将以他们结尾的并且总长度为n的个数记为mm[n],fm[n],mf[n],ff[n]。

考虑mm[n]后面加m是mm[n+1]的一部分,加f是mf[n+1]的一部分;

fm[n]加f属于O-queue,舍去,加m是mm[n+1]的一部分;

依次类推。。。。。。

得到递推式mm[n+1]=mm[n]+fm[n];    mf[n+1]=mm[n+1];   fm[n+1]=ff[n]+mf[n];    ff[n+1]=mf[n+1];

构造矩阵

|   mm[n]   mf[n]   fm[n]   ff[n]  |  *     |    1      1    0     0    
|

|     0     0    1     1     |

|     1     0    0     0  
  |

|     0     0    1     0     |

<span style="font-size:18px;">#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#define maxn 0+5
#define clr(x,y) memset(x,y,sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f;
typedef long long ll;
const double pi = acos( -1 );
const ll mod = 1e9+7;
int m;
struct matrix
{
    int n;
    ll maze[maxn][maxn];
    void init(int n)
    {
        this->n=n;
        clr(maze,0);
    }
    matrix operator * (const matrix& rhs)
    {
        matrix ans;
        ans.init(n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                    ans.maze[i][j]=(ans.maze[i][j]+maze[i][k]*rhs.maze[k][j])%m;
        return ans;
    }
};
matrix qlow(matrix a,int n)
{
    matrix ans;
    ans.init(a.n);
    for(int i=0;i<ans.n;i++)ans.maze[i][i]=1;
    while(n)
    {
        if(n&1)ans=ans*a;
        a=a*a;
        n>>=1;
    }
    return ans;
}
int main()
{
    //freopen("d:\\acm\\in.in","r",stdin);
    int l;
    while(~scanf("%d %d",&l,&m))
    {
        if(l<=2)
        {
            if(l==0)puts("0");
            else if(l==1)printf("%d\n",2%m);
            else printf("%d\n",4%m);
            continue;
        }
        matrix ans;
        ans.init(4);
        for(int i=0;i<4;i++)ans.maze[0][i]=1;
        matrix ant;
        ant.init(4);
        ant.maze[0][1]=ant.maze[1][3]=ant.maze[2][0]=ant.maze[2][1]=ant.maze[3][2]=ant.maze[3][3]=1;
        ant=qlow(ant,l-2);
        ans=ans*ant;
        int anw=0;
        for(int i=0;i<4;i++)anw=(anw+ans.maze[0][i])%m;
        printf("%d\n",anw);
    }
    return 0;
}</span>

第四题  hdu-2256

分析:一开始会以为与矩阵无关,但是看见根号还要取模就会发现满满都是套路。-。-虽然根号2与根号3是两个根号,但是还有个2次方,先将2次方乘进去,得到5+2sqrt(6),发现根号减少到一个,而且对于5+2sqrt(6)的n次方,一定是一个常数项和一个带根号6的项,而且互相之间有递推关系,这就把问题引向矩阵上了。

但是这里不能直接取模,因为Bn还有一部分是sqrt(6),直接取模显然是错的

这样构造的矩阵和最后要求的数据都有了 -。-

<span style="font-size:18px;">#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#define maxn 0+5
#define clr(x,y) memset(x,y,sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f;
typedef long long ll;
const double pi = acos( -1 );
const ll mod = 1024;//1e9+7;

struct matrix
{
    int n;
    ll maze[2][2];
    void init(int n)
    {
        this->n=n;
        clr(maze,0);
    }
    matrix operator * (const matrix& rhs)
    {
        matrix ans;
        ans.init(n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                    ans.maze[i][j]=(ans.maze[i][j]+maze[i][k]*rhs.maze[k][j])%mod;
        return ans;
    }
};
matrix qlow(matrix a,int n)
{
    matrix ans;
    ans.init(a.n);
    for(int i=0;i<ans.n;i++)ans.maze[i][i]=1;
    while(n)
    {
        if(n&1)ans=ans*a;
        a=a*a;
        n>>=1;
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        matrix ans;
        ans.init(2);
        ans.maze[0][0]=1;
        matrix ant;
        ant.init(2);
        ant.maze[0][0]=ant.maze[1][1]=5;
        ant.maze[0][1]=2;
        ant.maze[1][0]=12;
        ant=qlow(ant,n);
        ans=ans*ant;
        printf("%d\n",(2*ans.maze[0][0]-1)%mod);
    }
    return 0;
}</span>

第五题 codeforces-185A

分析:做完前面的题,这道题反而简单了。不妨考虑当n年后(操作n次),正三角的个数是An,倒三角的个数是Bn。那么继续再操作一次,An个正三角变成了3An个正三角和An个倒三角,Bn个倒三角变成Bn个正三角和3Bn个倒三角。所以有递推关系  An+1=3An+Bn    Bn+1=An+3Bn

构造矩阵

|  
An   Bn    |  *     |    3     1    |

|    1     3    |

<span style="font-size:18px;">#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#define maxn 0+5
#define clr(x,y) memset(x,y,sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f;
typedef long long ll;
const double pi = acos( -1 );
const ll mod = 1e9+7;

ll mul(ll a,ll b)
{
	ll ans=0;
	while(b)
	{
		if(b&1)ans=(ans+a)%mod;
		a=(a+a)%mod;
		b>>=1;
	}
	return ans;
}
struct matrix
{
	int n;
	ll maze[maxn][maxn];
	void init(int n)
	{
		this->n=n;
		clr(maze,0);
	}
	matrix operator * (const matrix& rhs)
	{
		matrix ans;
		ans.init(n);
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				for(int k=0;k<n;k++)
					ans.maze[i][j]=(ans.maze[i][j]+mul(maze[i][k],rhs.maze[k][j]))%mod;
		return ans;
	}
};
matrix qlow(matrix a,ll n)
{
	matrix ans;
	ans.init(a.n);
	for(int i=0;i<ans.n;i++)ans.maze[i][i]=1;
	while(n)
	{
		if(n&1)ans=ans*a;
		a=a*a;
		n>>=1;
	}
	return ans;
}
int main()
{
    //freopen("d:\\acm\\in.in","r",stdin);
	ll n;
	scanf("%I64d",&n);
	matrix ans;
	ans.init(2);
	ans.maze[0][0]=1;
	matrix ant;
	ant.init(2);
	ant.maze[0][0]=ant.maze[1][1]=3;
	ant.maze[1][0]=ant.maze[0][1]=1;
	ant=qlow(ant,n);
	ans=ans*ant;
	printf("%I64d\n",ans.maze[0][0]);
    return 0;
}</span>

第六题 hdu-2842

分析:题目讲的好像是九连环(好像又不是,英语不好),-。-    可怜我并没有玩过

这道题非常像汉诺塔,但是题目只是求最小步数,而不需要求出具体的步骤。我假设对于长度为i的中国环,我最少需要f(i)步(1<=i<=n)。那么对于长度为n+1的中国环,我们先考虑将最后一个拿下来(没办法,奇葩的规则,只有拿下前n-1个且保留第n个,才能拿下第n+1个)。那么先将前n-1个取下来,需要f(n-1)步;再将第n+1个取下来,需要1步;再把前n-1个放回去,需要f(n-1)步(这里需要解释一下,前n-1个必须放回去,不然第n个无法取下,而且取下需要f(n-1)步,那么放回去也需要f(n-1),直接相反的步骤再来一遍,不明白的多读几遍题目);最后,将前n个都取下,需要f(n)步。所以得到递推式
f(n+1)=f(n)+2f(n-1)+1。对于递推式中有常数项,只需要给出一行或列留给常数项。

构造矩阵

|    f(n)    f(n-1)    1     |  *     |    1    1    0    |

|    2    0    0    |

|    1    0    1    |

<span style="font-size:18px;">#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#define maxn 0+5
#define clr(x,y) memset(x,y,sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f;
typedef long long ll;
const double pi = acos( -1 );
const ll mod = 200907;//1e9+7;

struct matrix
{
    int n;
    ll maze[maxn][maxn];
    void init(int n)
    {
        this->n=n;
        clr(maze,0);
    }
    matrix operator * (const matrix& rhs)
    {
        matrix ans;
        ans.init(n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                    ans.maze[i][j]=(ans.maze[i][j]+maze[i][k]*rhs.maze[k][j])%mod;
        return ans;
    }
};
matrix qlow(matrix a,int n)
{
    matrix ans;
    ans.init(a.n);
    for(int i=0;i<ans.n;i++)ans.maze[i][i]=1;
    while(n)
    {
        if(n&1)ans=ans*a;
        a=a*a;
        n>>=1;
    }
    return ans;
}
int main()
{
    //freopen("d:\\acm\\in.in","r",stdin);
    int n;
    matrix ant;
    ant.init(3);
    ant.maze[0][0]=ant.maze[0][1]=ant.maze[2][0]=ant.maze[2][2]=1;
    ant.maze[1][0]=2;
    while(scanf("%d",&n),n)
    {
        if(n<=2)
        {
            if(n==1)printf("%d\n",1);
            else printf("%d\n",2);
            continue;
        }
        matrix ans;
        ans.init(3);
        ans.maze[0][0]=2;
        ans.maze[0][1]=ans.maze[0][2]=1;
        ans=ans*qlow(ant,n-2);
        printf("%I64d\n",ans.maze[0][0]);
    }
    return 0;
}</span>

第七题 hdu-2276

分析:对于01串,如果前一位的数位为1,那么这一位就翻转(0变1,1变0);前一位为0,那么这一位就不变。这就像前一位与这一位相加,并且mod2,如果前一位是0,那么这一位加上前一位再mod2数值不会改变;如果前一位是1,那么这一位就相当于+1mod2,正好和翻转的定义相同。这样我们就可以构造出矩阵

|    X    X    X    ...    X    |  *     |    1    1    0    ...   0    |

|    0    1    1    ...   0    |

|    0    0   1 ...  0    |

........

|    0    0    0    ...   1    |

|    1    0    0    ...   1    |

<span style="font-size:18px;">#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#define maxn 100+5
#define clr(x,y) memset(x,y,sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f;
typedef long long ll;
const double pi = acos( -1 );
const ll mod = 1e9+7;

char str[maxn];
struct matrix
{
    int n;
    ll maze[maxn][maxn];
    void init(int n)
    {
        this->n=n;
        clr(maze,0);
    }
    matrix operator * (const matrix & rhs)
    {
        matrix ans;
        ans.init(n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                    ans.maze[i][j]=(ans.maze[i][j]+maze[i][k]*rhs.maze[k][j])%2;
        return ans;
    }
};
matrix qlow(matrix a,int n)
{
    matrix ans;
    ans.init(a.n);
    for(int i=0;i<ans.n;i++)ans.maze[i][i]=1;
    while(n)
    {
        if(n&1)ans=ans*a;
        a=a*a;
        n>>=1;
    }
    return ans;
}
int main()
{
    //freopen("d:\\acm\\in.in","r",stdin);
    int m;
    while(~scanf("%d",&m))
    {
        scanf("%s",str);
        int n=strlen(str);
        matrix ans;
        ans.init(n);
        for(int i=0;i<n;i++)
            if(str[i]=='1')ans.maze[0][i]=1;
        matrix ant;
        ant.init(n);
        for(int i=0;i<n;i++)
        {
            ant.maze[i][i]=1;
            if(i==0)ant.maze[n-1][0]=1;
            else ant.maze[i-1][i]=1;
        }
        ant=qlow(ant,m);
        ans=ans*ant;
        for(int i=0;i<n;i++)
            printf("%d",ans.maze[0][i]);
        puts("");
    }
    return 0;
}</span>

第八题 hdu-2254

分析:学过离散数学的都知道,如果用邻接矩阵来存图的话,矩阵A的n次方里面的(A^n)[i][j]表示从i到j且路径长度为n的不同路径条数。这一定理正好适用这一题目。我用邻接矩阵来建图(单向边,一条边对应一个++操作)得到矩阵A,题目要求的就是{A^(t1)}[v1][v2]+{A^(t1+1)}[v1][v2]+{A^(t1+2)}[v1][v2]+......+{A^(t2)}[v1][v2]的和取模。但是如果一个一个算的话特别麻烦,还有超时的可能,所以我们进一步改进思路。

对于,我们不妨设Z(n)=A^1+A^2+...+A^n

那么可以构造递推关系 A^(n+1)=A^n * A      Z(n+1)=Z(n)+ A^(n+1) =Z(n)+A^n * A

构造矩阵

|    A^n   Z(n)     |  *     |    A    A    |

|    
0 0
  |    |    0    E    |

但是这道题目略坑,有几个注意点:

1、城市的编号不是从0到n-1,而是随便的一个数字,需要离散化否则不能存相关信息

2、城市数不超过30,也就是说我的方法开矩阵不超过60,但是我残念的一开始以为最多可能有20000个不同城市    血崩!

3、图中可能有重边,所以别用=1,要用++操作

4、询问中v1,v2可能在前面的城市编号集中没有出现,那么此时答案为0

5、t1可能比t2大,这种情况你就交换下t1,t2

这道题要做对也是真心不容易!

#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#define maxn 60+5
#define clr(x,y) memset(x,y,sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f;
typedef long long ll;
const double pi = acos( -1 );
const ll mod = 2008;//1e9+7;

ll gra[10000+5][2];
ll num[20000+5];
int sum;
int bs(ll k)
{
    int m,l=0,r=sum-1;
    while(l<=r)
    {
        m=(l+r)>>1;
        if(k==num[m])return m;
        else if(k>num[m])l=m+1;
        else r=m-1;
    }
    return -1;
}
struct matrix
{
    int n;
    ll maze[maxn][maxn];
    void init(int n)
    {
        this->n=n;
        clr(maze,0);
    }
    matrix operator * (const matrix & rhs)
    {
        matrix ans;
        ans.init(n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                    ans.maze[i][j]=(ans.maze[i][j]+maze[i][k]*rhs.maze[k][j])%mod;
        return ans;
    }
};
matrix qlow(matrix a,int n)
{
    matrix ans;
    ans.init(a.n);
    for(int i=0;i<a.n;i++)ans.maze[i][i]=1;
    while(n)
    {
        if(n&1)ans=ans*a;
        a=a*a;
        n>>=1;
    }
    return ans;
}
int main()
{
    //freopen("d:\\acm\\in.in","r",stdin);
    int n;
    while(~scanf("%d",&n))
    {
        sum=n*2;
        for(int i=0;i<n;i++)
        {
            scanf("%lld %lld",&gra[i][0],&gra[i][1]);
            num[i<<1]=gra[i][0];
            num[i<<1|1]=gra[i][1];
        }
        sort(num,num+sum);
        sum=unique(num,num+sum)-num;
        matrix ans;
        ans.init(sum<<1);
        matrix ant;
        ant.init(sum<<1);
        int a,b;
        for(int i=0;i<n;i++)
        {
            a=bs(gra[i][0]);
            b=bs(gra[i][1]);
            ans.maze[a][b]++;
            ans.maze[a][b+sum]++;
        }
        for(int i=0;i<sum;i++)
            ans.maze[i+sum][i+sum]=1;
        int q;
        scanf("%d",&q);
        while(q--)
        {
            int t1,t2;
            ll v1,v2;
            scanf("%lld %lld %d %d",&v1,&v2,&t1,&t2);
            v1=bs(v1);
            v2=bs(v2);
            if(v1==-1||v2==-1)
            {
                puts("0");
                continue;
            }
            if(t1>t2)swap(t1,t2);
            t1--;
            int d,d1,d2;
            if(t1<=0)d1=0;
            else
            {
                ant=qlow(ans,t1);
                d1=ant.maze[v1][v2+sum];
            }
            if(t2<=0)d2=0;
            else
            {
                ant=qlow(ans,t2);
                d2=ant.maze[v1][v2+sum];
            }
            d=d2-d1;
            while(d<0)d+=mod;
            printf("%d\n",d);
        }
    }
    return 0;
}

第九题 hdu-3117

分析:其实这道题不应该放在矩阵快速幂专题的,因为这道题关于矩阵的部分很简单-。-,难的是题目的数学部分-。-

求解斐波那契数列的值,对于数值位不超过8位的直接输出数值;但是对于大于8位的,输出值的前四位和后四位(格式自己看-。-)。后四位当然非常简单了,f(n)=f(n-1)+f(n-2) ,mod 10000,我就不再赘述了

但是对于前四位还是挺麻烦的,这里要用到对数的优良性质。

这里就不细说了 ,详情请看大神的博客 http://blog.sina.com.cn/s/blog_9bf748f301019q3t.html

<span style="font-size:18px;">#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#define maxn 60+5
#define clr(x,y) memset(x,y,sizeof(x))
using namespace std;
const int inf = 0x3f3f3f3f;
typedef long long ll;
const double pi = acos( -1 );
const ll mod = 10000;//1e9+7;

int fa[60];
struct matrix
{
    int n;
    ll maze[5][5];
    void init(int n)
    {
        this->n=n;
        clr(maze,0);
    }
    matrix operator * (const matrix & rhs)
    {
        matrix ans;
        ans.init(n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                for(int k=0;k<n;k++)
                    ans.maze[i][j]=(ans.maze[i][j]+maze[i][k]*rhs.maze[k][j])%mod;
        return ans;
    }
};
matrix qlow(matrix a,int n)
{
    matrix ans;
    ans.init(a.n);
    for(int i=0;i<a.n;i++)ans.maze[i][i]=1;
    while(n)
    {
        if(n&1)ans=ans*a;
        a=a*a;
        n>>=1;
    }
    return ans;
}
int main()
{
    //freopen("d:\\acm\\in.in","r",stdin);
    fa[0]=0;
    fa[1]=1;
    for(int i=2;i<40;i++)
        fa[i]=fa[i-1]+fa[i-2];
    int n;
    while(~scanf("%d",&n))
    {
        if(n<40)
        {
            printf("%d\n",fa[n]);
            continue;
        }
        double p=(sqrt(5.0)+1.0)/2.0;
        double s=1.0*n*log10(p)-log10(5.0)/2;
        s=s-(int)s;
        int anw=(int)(pow(10.0,s)*1000);
        printf("%d...",anw);
        matrix ant;
        ant.init(2);
        ant.maze[0][0]=ant.maze[0][1]=ant.maze[1][0]=1;
        ant=qlow(ant,n-1);
        printf("%04d\n",ant.maze[0][0]);
    }
    return 0;
}</span>
时间: 2024-12-25 20:46:51

矩阵快速幂专题(一)的相关文章

矩阵快速幂专题(三)

哈哈哈,博主又回来了!这次专题是第三弹也是最后一弹了,这次会对矩阵进行一个小收尾.做完这25道题,我感觉到其实我矩阵学得并不好,还有许多知识点没有学会.后面看情况可能还会继续开矩阵的专题,那应该是几个月以后的事了.从下周开始,应该会先学习一下数论的相关算法! 这次的七道题目(为什么题目越来越少了)主要是针对了矩阵的优化,对于会TLE的和MLE(内存爆了)的矩阵而且这个矩阵又恰好是同构矩阵(同构矩阵是啥?)的话,可以采用一维数组来模拟二维,从而降低复杂度.降低空间.(竟然是罕见的同时降时间和空间的

矩阵快速幂 专题

poj 3233 Matrix Power Series http://poj.org/problem?id=3233 /************************************************************** Problem:poj 3233 User: youmi Language: C++ Result: Accepted Time:1735MS Memory:3880K *****************************************

HDU 4549 M斐波那契数列(矩阵快速幂&amp;费马小定理)

ps:今天和战友聊到矩阵快速幂,想到前几天学长推荐去刷矩阵专题,挑了其中唯一一道中文题,没想到越过山却被河挡住去路... 题目链接:[kuangbin带你飞]专题十九 矩阵 R - M斐波那契数列 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u 题意 Description M斐波那契数列F[n]是一种整数数列,它的定义如下: F[0] = a F[1] = b F[n] = F[n-1] * F[n-2]

矩阵快速幂刷题系列

来源自http://blog.csdn.net/chenguolinblog/article/details/10309423 hdu 1575 Tr A Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5587    Accepted Submission(s): 4200 Problem Description A为一个方阵,则Tr

HDU 1757 A Simple Math Problem (矩阵快速幂)

[题目链接]:click here~~ [题目大意]: If x < 10 f(x) = x. If x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + -- + a9 * f(x-10); 问f(k)%m的值. [思路]:矩阵快速幂,具体思路看代码吧,注意一些细节. 代码: #include<bits/stdc++.h> using namespace std; typedef long long LL; const

Codeforces Round #291 (Div. 2) E - Darth Vader and Tree (DP+矩阵快速幂)

这题想了好长时间,果断没思路..于是搜了一下题解.一看题解上的"快速幂"这俩字,不对..这仨字..犹如醍醐灌顶啊...因为x的范围是10^9,所以当时想的时候果断把dp递推这一方法抛弃了.我怎么就没想到矩阵快速幂呢.......还是太弱了..sad..100*100*100*log(10^9)的复杂度刚刚好. 于是,想到了矩阵快速幂后,一切就变得简单了.就可以把距离<=x的所有距离的点数都通过DP推出来,然后一个快速幂就解决了. 首先DP递推式很容易想到.递推代码如下: for(

POJ 3233 - Matrix Power Series ( 矩阵快速幂 + 二分)

POJ 3233 - Matrix Power Series ( 矩阵快速幂 + 二分) #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; #define MAX_SIZE 30 #define CLR( a, b ) memset( a, b, sizeof(a) ) int MOD = 0; int n, k; st

HDU 4990 Reading comprehension(找规律+矩阵快速幂)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4990 Problem Description Read the program below carefully then answer the question. #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include<iostream> #include

hdu 6198(矩阵快速幂)

number number number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 175    Accepted Submission(s): 119 暴力发现当4 12 33 88 232 和斐波那契数列对比  答案为 第2*k+3个数减1 直接用矩阵快速幂求的F[2*k+3]  然后减1 A=1,B=0; 然后矩阵快速幂2*k