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),也不小-_-|||

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