解题报告 之 HDU5318 The Goddess Of The Moon

解题报告 之 HDU5318 The Goddess Of The Moon


Description

Chang’e (嫦娥) is a well-known character in Chinese ancient mythology. She’s the goddess of the Moon. There are many tales about Chang'e, but there's a well-known story regarding the origin of the Mid-Autumn Moon Festival. In a very distant past, ten suns had risen together to the heavens, thus causing hardship for the people. The archer Yi shot down nine of them and was given the elixir of immortality as a reward, but he did not consume it as he did not want to gain immortality without his beloved wife Chang'e. 



However, while Yi went out hunting, Fengmeng broke into his house and forced Chang'e to give up the elixir of immortality to him, but she refused to do so. Instead, Chang'e drank it and flew upwards towards the heavens, choosing the moon as residence to be nearby her beloved husband. 



Yi discovered what had transpired and felt sad, so he displayed the fruits and cakes that his wife Chang'e had liked, and gave sacrifices to her. Now, let’s help Yi to the moon so that he can see his beloved wife. Imagine the earth is a point and the moon is also a point, there are n kinds of short chains in the earth, each chain is described as a number, we can also take it as a string, the quantity of each kind of chain is infinite. The only condition that a string A connect another string B is there is a suffix of A , equals a prefix of B, and the length of the suffix(prefix) must bigger than one(just make the joint more stable for security concern), Yi can connect some of the chains to make a long chain so that he can reach the moon, but before he connect the chains, he wonders that how many different long chains he can make if he choose m chains from the original chains.
 

Input

The first line is an integer T represent the number of test cases. 
Each of the test case begins with two integers n, m. 
(n <= 50, m <= 1e9) 
The following line contains n integer numbers describe the n kinds of chains. 
All the Integers are less or equal than 1e9. 
 

Output

Output the answer mod 1000000007.
 

Sample Input

     
     
2 10 50 12 1213 1212 1313231 12312413 12312 4123 1231 3 131 5 50 121 123 213 132 321
 

Sample Output

     
     
86814837 797922656

Hint

11 111 is different with 111 11
 

题目大意:忽略阅读理解的部分,抽象出来就是,给出n个由数字组成的串,两个串的首位如果有两个或以上字符相同,则可以重叠合并为一个长串。现在让你从中选取m个串(可以重复选),组成一个新的长串,问有几种组合方法?

分析:这篇文章启发挺大的,之前蓝桥杯因为没做出类似题就没去成北京,真是太遗憾了。。。所以这次遇到这个题也算是很棒,对类似问题有很好的引导作用。先吐槽一下鸡肋的故事背景和诡异的图片。然后开始分析,在这里请允许我盗图。

首先一点就是去重,既然已经可以选重复的了,那么输入给出的重复串就没必要出现而且会使得结果出错。去重完成后先举一个例子。
比如现在给出五个串,我们用A A B C A来编号他们,去掉重复的,则剩下A B C 三种,经过判断发现AA,AB,AC,BB,CC,CB是可以连接成为新串的。

那么m=1,则可以选择A,B,C三种;
       m=2,则可以有AA,AB,AC,BB,CC,CB六种;
       m=3,则可以有AAA,AAB,AAC ;  ABC ;  ACC,ACB ;  BBB ;  CCC,CCB ;  CBB 十种。
       m=4,则可以有AAAA,AAAB,AAAC;AABB;AACC,AACB,ABCC,ABCB;ACCC,ACCB;ACBB;BBBB;CCCC,CCCB;CCCB 十五中。



以此类推……我们可以看到m每增加1,都是根据m-1和m=2来生成的,所以说有了m=2和m-1,我们就可以往后递推了。
a[i][m-1]表示以编号为 i 的字符串为最后一个,一共选了m-1个串的情况数,那么乘上右边这个表示是否可以连接的矩阵后就是选择m个串的情况数了。(矩阵乘法请自行复习。。。)。


所以对于这道题,我们先生成一个第一排全部为1的矩阵,然后根据连接情况生成连接矩阵,再连续乘m-1次,最后把结果矩阵的第一行相加就是最终的情况数了。


注意乘的时候用矩阵快速幂,因为乘的次数高达1e9次。(矩阵快速幂可以参考另一篇博文,快速幂详解,只是乘的时候换成矩阵即可)

上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<set>
using namespace std;

const int MAXN = 50 + 10;
const int MOD = 1e9 + 7;
typedef long long ll;

struct matrix
{
	ll num[MAXN][MAXN];
	matrix()
	{
		memset( num, 0, sizeof num );
	}
};

matrix mul( matrix a, matrix b, int n )
{
	matrix tem;
	for(int i = 0; i < n; i++)
		for(int j = 0; j < n; j++)
			if(a.num[i][j])
				for(int k = 0; k < n; k++)
					tem.num[i][k] = (tem.num[i][k] + a.num[i][j] * b.num[j][k]) % MOD;

	return tem;
}

matrix quick_pow( matrix a, ll p, int n )
{
	matrix tem;
	for(int i = 0; i < n; i++)
		tem.num[i][i] = 1;

	while(p)
	{
		if(p & 1)
		{
			tem = mul( a, tem, n );
		}
		a = mul( a, a, n );
		p /= 2;
	}
	return tem;
}


int judge( string a, string b )
{
	int i, j, flag;
	for(i = 2; i <= a.size() && i <= b.size(); i++)
	{
		flag = 1;
		for(j = 0; j<i; j++)
		{
			if(a[a.size() - i + j] != b[j])
				flag = 0;
		}
		if(flag)
			return 1;
	}
	return 0;
}

int main()
{
	set<string> s;
	string chain[MAXN];

	int kase, n, m;
	cin >> kase;
	while(kase--)
	{
		scanf( "%d%d", &n, &m );
		s.clear();
		int cnt = 0;
		for(int i = 0; i < n; i++)
		{
			string tem;
			cin >> tem;
			if(s.find( tem ) == s.end())
			{
				s.insert( tem );
				chain[cnt++] = tem;
			}
		}

		if(m == 0 || n == 0)
		{
			cout << 0 << endl;
			continue;
		}
		matrix ini, con;
		for(int i = 0; i < cnt; i++)
		{
			for(int j = 0; j < cnt; j++)
			{
				if(judge( chain[i], chain[j] ))
					con.num[i][j] = 1;
			}
		}
		for(int i = 0; i < cnt; i++)
			ini.num[0][i] = 1;

		ini = mul( ini, quick_pow( con, m - 1, cnt ),cnt );

		ll ans = 0;

		for(int i = 0; i < cnt; i++)
		{
			ans += ini.num[0][i];
			ans %= MOD;
		}
		cout << ans << endl;
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值