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

#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;
}
/*
【题意】

【类型】

【分析】

aij表示图案i可以在右侧仿制出图案j

【时间复杂度&&优化】

AE
OE

AB
CD
B就等于A^0+A^1+A^2+...+A^m

===========★再看看题解构造法★============

AB
CD

AB0
CD0
111

AB0 AB0
CD0 CD0
111 111

AB0
CD0
XX1的样子，太巧妙了。即只要加一行就可以AC啦。

*/

• 本文已收录于以下专栏：

举报原因： 您举报文章：【HDU5411 2015 Multi-University Training Contest 10F】【矩阵快速幂 加一行构造法】CRB and Puzzle 矩阵的1次方到n次方的数值和 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)