Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) |
#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啦。
*/