1. 程式人生 > >牛客小白月賽6 洋灰三角(詳解)

牛客小白月賽6 洋灰三角(詳解)

洋灰三角

時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 262144K,其他語言524288K
64bit IO Format: %lld

題目描述

    洋灰是一種建築材料,常用來築橋搭建高層建築,又稱,水泥、混凝土。

    WHZ有很多鑄造成三角形的洋灰塊,他想把這些洋灰三角按照一定的規律放到擺成一排的n個格子裡,其中第i個格子放入的洋灰三角數量是前一個格子的k倍再多p個,特殊地,第一個格子裡放1個。
    WHZ想知道把這n個格子鋪滿需要多少洋灰三角。

輸入描述:

第一行有3個正整數n,k,p。

輸出描述:

輸出一行,一個正整數,表示按照要求鋪滿n個格子需要多少洋灰三角,由於輸出資料過大,你只需要輸出答案模1000000007(1e9+7)後的結果即可。

示例1

輸入

複製

3 1 1

輸出

複製

6

說明

洋灰三角鋪法:1 2 3,總計6個

示例2

輸入

複製

3 2 2

輸出

複製

15

說明

洋灰三角鋪法:1 4 10,總計15個

示例3

輸入

複製

3 3 3

輸出

複製

28

說明

洋灰三角鋪法:1 6 21,總計28個

備註:

對於100%的測試資料:
1 ≤ n ≤ 1000000000
1 ≤ k,p ≤ 1000

大致思路:

           首先,我們很容易得到這兩個表示式:sum(n)=sum(n-1)+a(n),a(n)=k*a(n-1)+p。

           顯然,常規思路求sum(n),就一定求知道sum(n-1),a(n);

           但是,對於大規模的資料,這樣操作肯定是不行的。我們要知道另一種更加普遍高效的演算法。矩陣快速冪。

比如說我們可以構造一個等比矩陣。使其A[n]=T^(n-1)*A[1],  (其中,n>1), 這樣 ,我們僅僅需要知道矩陣T,A[1],就能

很快的求出A[n];

         現在,我們來嘗試構造這個矩陣A,以及公比矩陣T:

因                             sum(n)  =  sum(n-1) + a(n)

又                               a(n)     =  k*a(n-1) + p

則                              sum(n) = sum(n-1) +  k*a(n-1) + p

由矩陣相乘性質有:

T[0]={1,k,1}                                               (或T[0]={1,k,p}等,只要能構造成功、自圓其說即可)

                                       sum(n-1) 

故                 A(n-1) = {      a(n-1)        }

                                             p

因此

                                   sum(n) 

              A(n-1) = {        a(n)        }

                                        p

於是解得

         1      k       1

T= {   0      k       1 }

         0      0       1      

    1      k    1        sum(n-1)        sum(n)
                                  
    0      k    1     ×   a(n-1)     =     a(n)
          
    0      0    1            p                    p

或者

    1      k    p         sum(n-1)        sum(n)
                                    
    0      k    p     ×     a(n-1)    =     a(n)
          
    0      0    1              1                   1

ac程式碼如下

# include <iostream>
# include <cstring>
# define ll long long

using namespace std;

const ll mod = 1e9+7;

ll n,k,p;

struct matrix
{
	ll m[5][5];
	
}ans,res;//res為T矩陣,ans為A(n)

void init()
{
	memset(res.m,0,sizeof res.m);//構造T矩陣
	res.m[1][1]=1;
	res.m[1][2]=k;
	res.m[1][3]=1;
	res.m[2][1]=0;
	res.m[2][2]=k;
	res.m[2][3]=1;
	res.m[3][1]=0;
	res.m[3][2]=0;
	res.m[3][3]=1;
	return ;
}

matrix calc(matrix a,matrix b)//矩陣相乘
{
	matrix tmp;
	for(int i=1;i<=3;i++)
		for(int j=1;j<=3;j++)
			tmp.m[i][j]=0;
			
	for(int i=1;i<=3;i++)
		for(int j=1;j<=3;j++)
			for(int k=1;k<=3;k++)
			{
				tmp.m[i][j]+=a.m[i][k]*b.m[k][j];
				tmp.m[i][j]%=mod;
			}
				
				
	return tmp;
}

void quick_pow(int n)//矩陣快速冪
{
	for(int i=1;i<=3;i++)//單位矩陣
		for(int j=1;j<=3;j++)
		{
			if(i==j)
				ans.m[i][j]=1;
			else
				ans.m[i][j]=0;
		}
	
	while(n)
	{
		if(n&1) ans=calc(ans,res);
		res=calc(res,res);
		n>>=1;
	}
}


int main()
{
	cin>>n>>k>>p;
	ll sum=0;
	
	if(n==2)
	{
		sum+=k+p+1;
		sum%=mod;
		cout<<sum<<endl;
		return 0;
	}
	
	if(n==1)
	{
		cout<<"1"<<endl;
		return 0;
	}
	init();
	quick_pow(n-1);
	sum+=(ans.m[1][1]+ans.m[1][2]+ans.m[1][3]*p)%mod;
	cout<<sum<<endl;
	return 0;
}