牛客小白月賽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;
}