cf Educational Codeforces Round 60 D. Magic Gems

原題:
D. Magic Gems

time limit per test3 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output

Reziba has many magic gems. Each magic gem can be split into M normal gems. The amount of space each magic (and normal) gem takes is 1 unit. A normal gem cannot be split.

Reziba wants to choose a set of magic gems and split some of them, so the total space occupied by the resulting set of gems is N units. If a magic gem is chosen and split, it takes M units of space (since it is split into M gems); if a magic gem is not split, it takes 1 unit.

How many different configurations of the resulting set of gems can Reziba have, such that the total amount of space taken is N units? Print the answer modulo 1000000007 (109+7). Two configurations are considered different if the number of magic gems Reziba takes to form them differs, or the indices of gems Reziba has to split differ.

Input
The input contains a single line consisting of 2 integers N and M (1≤N≤10^18, 2≤M≤100).

Output
Print one integer, the total number of configurations of the resulting set of gems, given that the total amount of space taken is N units. Print the answer modulo 1000000007 (10^9+7).

Examples
input
4 2
output
5
input
3 2
output
3
Note
In the first example each magic gem can split into 2 normal gems, and we know that the total amount of gems are 4.

Let 1 denote a magic gem, and 0 denote a normal gem.

The total configurations you can have is:

1111 (None of the gems split);
0011 (First magic gem splits into 2 normal gems);
1001 (Second magic gem splits into 2 normal gems);
1100 (Third magic gem splits into 2 normal gems);
0000 (First and second magic gems split into total 4 normal gems).
Hence, answer is 5.

中文:
給你一堆個魔法寶石一字排開,每個魔法寶石可以變成m個普通寶石,現在問你構造長度爲n的寶石擺放有多少種方式?可以看第一個樣例和解釋。

代碼:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const ll mod = 1000000007;
const int maxn = 100;

typedef vector<ll> vec;
typedef vector<vec> mat;



mat mul(mat &A,mat &B)
{
	mat C(A.size(),vec(B[0].size()));
	for(int i=0;i<A.size();i++)
	{
		for(int k=0;k<B.size();k++)
		{
			for(int j=0;j<B[0].size();j++)
			{
				C[i][j]=(C[i][j]+A[i][k]*B[k][j]);
				if(C[i][j]>=mod)
					C[i][j]%=mod;
			}
		}
	}
	return C;
}


mat pow_mat(mat &A,ll n)
{
	mat B(A.size(),vec(A.size()));
	for(int i=0;i<A.size();i++)
	{
		B[i][i]=1;
	}
	while(n>0)
	{
		if(n&1)B = mul(B,A);
		A = mul(A,A);
		n>>=1;
	}
	return B;
}



int main()
{

	ios::sync_with_stdio(false);
	ll n,m;
	while(cin>>n>>m)
	{

		mat M(m,vec(m));
		M[0][0]=M[0][m-1]=1;

        for(int i=1;i<m;i++)
			M[i][i-1]=1;

		if(n<m)
		{
			cout<<1<<endl;
			continue;
		}
        M = pow_mat(M,n-m+1);

		ll ans=0;
		for(int i=0;i<m;i++)
        {
            ans+=M[0][i];
            if(ans>=mod)
                ans-=mod;
        }

		cout<<ans<<endl;

	}
	return 0;
}


解答:

如果對組合數學或者遞推比較熟悉,很快就能列出這道題的組合公式或者遞推公式。如果考慮使用組合公式計算,可以看做先在桌子上擺放n個魔法寶石,取某些連續的m個魔法寶石替換成普通寶石,這樣就是一種組合方式了。
公式也很簡單:

k=0(nk(m1)k) \sum\limits_{k=0}\binom{n-k(m-1)}{k}

但是看數據,可以發現n的取值範圍達到了10^18,根本不可能使用任何遍歷的手段實現。如果考慮上面的組合數公式是否能夠變形或者優化成一個能在O(1)方法實現,那此題就成功的套住你了,畢竟解決10 ^18數據問題的方法很少會去找處理過繁瑣的方法(我就被套住了-_-|||)

如果考慮用遞推的方式解決,那麼狀態轉移方程也是非常簡單:
dp[n]=dp[nm]+dp[n1] dp[n]=dp[n-m]+dp[n-1]
表示長度爲n的排列寶石,的組合方式可以來自於在n-1寶石排列中添加一個寶石,以及在n-m個寶石中,添加一個魔法寶石。

處理至此,仍然會發現數據n的數量級根本無法保存狀態,咋辦?

如果看到題解恍然大悟立刻知道怎麼做的話,那你肯定是做過這樣一道題,給你一個斐波那契數列,讓你快速找出該斐波那契數列的第n項,這個n可能非常大,在不用通項公式的情況,有這樣一種辦法,將遞推關係寫成矩陣的形式,然後利用矩陣相乘的遞推關係得到變換矩陣A的x次冪乘以初項即可快速得到最終結果。如此一來可以利用快速冪方法處理高次方,就能得到答案。

本題的矩陣遞推方法如下:

根據上面的遞推方程,可以寫成下面的形式

[dpndpn1...dpnm+1]=[1000...11000...0...000...10][dpn1dpn2...dpnm] \begin{bmatrix} dp_n\\ dp_{n-1}\\ ...\\ dp_{n-m+1} \end{bmatrix} = \begin{bmatrix} 1&amp;0&amp;0&amp;0&amp;...&amp;1\\ 1&amp;0&amp;0&amp;0&amp;...&amp;0\\ &amp;&amp;...\\ 0&amp;0&amp;0&amp;...&amp;1&amp;0 \end{bmatrix} \begin{bmatrix} dp_{n-1}\\ dp_{n-2}\\ ...\\ dp_{n-m} \end{bmatrix}
那麼,如果要計算dpndp_n
[dpndpn1...dpnm+1]=[1000...11000...0...000...10]nm+1[dpm1dpm2...dp0] \begin{bmatrix} dp_n\\ dp_{n-1}\\ ...\\ dp_{n-m+1} \end{bmatrix} = \begin{bmatrix} 1&amp;0&amp;0&amp;0&amp;...&amp;1\\ 1&amp;0&amp;0&amp;0&amp;...&amp;0\\ &amp;&amp;...\\ 0&amp;0&amp;0&amp;...&amp;1&amp;0 \end{bmatrix}^{n-m+1} \begin{bmatrix} dp_{m-1}\\ dp_{m-2}\\ ...\\ dp_{0} \end{bmatrix}

時間複雜度是O(m^3logn),也不小-_-|||

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章