【HDU5411 2015 Multi-University Training Contest 10F】【矩阵快速幂 加一行构造法】CRB and Puzzle 矩阵的1次方到n次方的数值和


CRB and Puzzle

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 877    Accepted Submission(s): 351


Problem Description
CRB is now playing Jigsaw Puzzle.
There are   N  kinds of pieces with infinite supply.
He can assemble one piece to the right side of the previously assembled one.
For each kind of pieces, only restricted kinds can be assembled with.
How many different patterns he can assemble with at most   M  pieces? (Two patterns   P  and   Q  are considered different if their lengths are different or there exists an integer   j  such that   j -th piece of   P  is different from corresponding piece of   Q .)
 

Input
There are multiple test cases. The first line of input contains an integer   T , indicating the number of test cases. For each test case:
The first line contains two integers   N ,   M  denoting the number of kinds of pieces and the maximum number of moves.
Then   N  lines follow.   i -th line is described as following format.
k   a1 a2 ... ak
Here   k  is the number of kinds which can be assembled to the right of the   i -th kind. Next   k  integers represent each of them.
1 ≤   T  ≤ 20
1 ≤   N  ≤ 50
1 ≤   M    105
0 ≤   k    N
1 ≤   a1  <   a2  < … <   ak  ≤ N

 

Output
For each test case, output a single integer - number of different patterns modulo 2015.
 

Sample Input
       
       
       
       
1 3 2 1 2 1 3 0
 

Sample Output
       
       
       
       
6
Hint
possible patterns are ∅, 1, 2, 3, 1→2, 2→3
 

Author
KUT(DPRK)
 

Source
2015 Multi-University Training Contest 10
 



#include<stdio.h>
#include<iostream>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<functional>
#include<string>
#include<algorithm>
#include<time.h>
#include<bitset>
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
typedef int Int;
template <class T> inline void gmax(T &a,T b){if(b>a)a=b;}
template <class T> inline void gmin(T &a,T b){if(b<a)a=b;}
using namespace std;
const int N=51,M=0,L=0,Z=2015,maxint=2147483647,ms31=522133279,ms63=1061109567,ms127=2139062143;
const double eps=1e-8,PI=acos(-1.0);//.0
map<int,int>mop;
struct A{};
int casenum,casei;
int n,m,nn;
struct MX
{
	int v[N][N];
	void O(){MS(v,0);}//得到零矩阵
	void E(){MS(v,0);for(int i=0;i<nn;i++)v[i][i]=1;}//得到单位矩阵
	MX operator * (const MX &b) //const 这个const 有什么用处呢——确保我们不改变b的值
	{
		MX c;c.O();
		for(int k=0;k<nn;k++)
		{
			for(int i=0;i<nn;i++)
			{
				for(int j=0;j<nn;j++)
				{
					c.v[i][j]=(c.v[i][j]+v[i][k]*b.v[k][j]);
				}
			}
		}
		for(int i=0;i<nn;i++)
		{
			for(int j=0;j<nn;j++)c.v[i][j]%=Z;
		}
		/*
		计算的大量时间浪费在取模上了。
		v[i,j]最多只能累计2015*2015*100的权值,也就是4e8,不会爆int
		这样优化就AC了。
		*/
		return c;
	}
	MX operator ^ (int p)
	{
		MX x;x.E();//初始化单位矩阵
		MX y;MC(y.v,v);
		while(p)
		{
			if(p&1)x=x*y;
			p/=2;
			y=y*y;
		}
		return x;
	}
}a;
int main()
{
	//fre();
	scanf("%d",&casenum);
	for(casei=1;casei<=casenum;casei++)
	{
		a.O();
		scanf("%d%d",&n,&m);
		for(int i=0;i<n;i++)
		{
			int k,x;scanf("%d",&k);
			for(int j=0;j<k;j++)
			{
				scanf("%d",&x);
				a.v[i][x-1]=1;
			}
		}
		for(int i=0;i<=n;i++)a.v[i][n]=1;
		nn=n+1;a=a^(m-1);//运算^m得到的是E+A+A^2+...+A^(m-1)
		int ans=0;
		for(int i=0;i<nn;i++)
		{
			for(int j=0;j<nn;j++)ans+=a.v[i][j];
		}
		printf("%d\n",ans%Z);
	}
	return 0;
}
/*
【题意】
有n(1<=n<=50)种纸片,每种无限个。
我们每次可以仿制一张卡片,放到被仿制卡片的右边。
我们想知道,使用0~m(1<=m<=1e5)张纸后可以创造出多少种图案。

【类型】
矩阵快速幂

【分析】
一开始首先我们得到的是一个矩阵。
aij表示图案i可以在右侧仿制出图案j
然后就矩阵快速幂搞一下就可以啦~

【时间复杂度&&优化】
然而这道题,我用的是一个技巧。
求A^0+A^1+A^2+...+A^m,可以构造这样的矩阵——
AE
OE
然后上面那个矩阵做^(m+1),然后得到矩阵——
AB
CD
B就等于A^0+A^1+A^2+...+A^m

只是这种方法使得常数扩大了8倍,也许会导致TLE
于是我们还要用迭代法试试看,然后也TLE
然而如果做了取模优化了,还是能够就AC,只是并不快>_<

===========★再看看题解构造法★============
时间效率快了至少5倍啊!太厉害了!
是怎么实现的呢?
设原矩阵为
AB
CD
那么新矩阵就成了
AB0
CD0
111
如果m=1,我们返回a^0,即单位矩阵,只存在对角线元素n+1个
如果m=2,我们返回a^1,即如下原矩阵,结果也对
AB0 AB0
CD0 CD0
111 111
如果m=3,对于我们返回的矩阵
左上角的n*n矩阵依然会得到原矩阵平方的结果,也就相当于求得了A^2
然后下面这个111……就把之前的全部结果都存进来了
而且形成的矩阵永远是
AB0
CD0
XX1的样子,太巧妙了。即只要加一行就可以AC啦。

*/


你可能感兴趣的:(矩阵快速幂,构造,题库-HDU)