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啦。 */