HDU 5411 CRB and Puzzle(矩阵快速幂+可达矩阵)
2015-08-22 00:51
543 查看
HDU 5411
题意:
Count the number of different patterns by counting the number of different paths of length at most m-1.思路:
其实这类问题就是求:S=I+A+A2+...+AmS=I+A+A^2+...+A^m
一般普适的计算方式是:
(AmS)=(AI0I)m∗(I0)\left(
\begin{array}{ccc}
A^m\\
S\\
\end{array}
\right)
=\left(
\begin{array}{ccc}
A & 0\\
I & I\\
\end{array}
\right)^m
*
\left(
\begin{array}{ccc}
I\\
0\\
\end{array}
\right)
这样做的好处是可以得到最后的矩阵S,然后求S的所有元素和即是答案-1(没统计∅\emptyset),不过这题n <= 50 ,矩阵大小可能会超过100*100,时间复杂度将达到O(N3logM)O(N^3\log M)再加上数据有20组,会被卡常数TLE,但有一个办法就是将矩阵乘法的取模操作从最内层移到第二层(因为mod只有2015,也就是说矩阵最大元素只有2014,最内层的乘法加法操作不会爆int),可以进行一定常数优化,,刚好可以卡着时间AC(大概480ms)
但是这题并不需要我们求出最后的加和矩阵S,仅需要它的各项元素和即可,那么我们可以把这个矩阵简化成这样(假设邻接是个四阶矩阵):
⎛⎝⎜⎜⎜⎜⎜⎜11A1100001⎞⎠⎟⎟⎟⎟⎟⎟m=⎛⎝⎜⎜⎜⎜⎜⎜a1a2Ama3a40000a5⎞⎠⎟⎟⎟⎟⎟⎟\left(
\begin{array}{ccc}
&&& &0\\
&&&& 0\\
&&A& &0\\
&&&& 0\\
1& 1&1&1&1\\
\end{array}
\right)^m=
\left(
\begin{array}{ccc}
&&& &0\\
&&&& 0\\
&&A^m& &0\\
&&&& 0\\
a_1& a_2&a_3&a_4&a_5\\
\end{array}
\right)
ans=∑ni=1aians=\sum_{i=1}^na_i
这样做就避免了空间的浪费,且保留下来了答案,当然这里初始矩阵的最下面一行1也可以放去最上层,最左层,最右层,因为是计算AkA^k所有元素和,并无影响。
这种做法复杂度与之前一致,但因为矩阵大小降了近乎一半,耗时相对少了很多(大概93msAC)
代码:
方法1:
[code]/* * @author FreeWifi_novicer * language : C++/C */ #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #include<queue> using namespace std; #define clr( x , y ) memset(x,y,sizeof(x)) #define cls( x ) memset(x,0,sizeof(x)) #define mp make_pair #define pb push_back typedef long long lint; typedef long long ll; typedef long long LL; const int maxn = 100 + 5 ; const int mod = 2015 ; struct Matrix { int n , m ; int a[maxn][maxn] ; Matrix( int n , int m ){ this->n = n ; this->m = m ; cls(a) ; } Matrix operator * ( const Matrix &tmp ){ Matrix res( n , tmp.m ) ; for( int i = 0 ; i < n ; i++ ){ for( int j = 0 ; j < tmp.m ; j++ ){ for( int k = 0 ; k < m ; k++ ) res.a[i][j] += a[i][k] * tmp.a[k][j] ; if( res.a[i][j] > mod ) res.a[i][j] %= mod ; } } return res ; } }; void Matrix_print( Matrix x ){ for( int i = 0 ; i < x.n ; i++ ){ for( int j = 0 ; j < x.m ; j++ ){ cout << x.a[i][j] << ' '; } cout << endl; } cout << endl ; } Matrix fast_pow( Matrix x , int n ){ Matrix res( x.n , x.m ) ; for( int i = 0 ; i < x.n ; i++ ) res.a[i][i] = 1 ; while( n ){ if( n & 1 ) res = res * x ; n >>= 1 ; x = x * x ; } return res ; } int main(){ // freopen("input.txt","r",stdin); int t ; cin >> t ; while( t-- ){ int n , m ; cin >> n >> m ; Matrix G( 2 * n , 2 * n ) ; for( int i = 0 ; i < n ; i++ ){ int k ; scanf( "%d" , &k ) ; for( int j = 0 ; j < k ; j++ ){ int tmp ; scanf( "%d" , &tmp ) ; G.a[i][tmp-1] = 1 ; } } for( int i = n ; i < 2 * n ; i++ ){ G.a[i][i - n] = 1 ; G.a[i][i] = 1 ; } Matrix base( 2 * n , n ) ; for( int i = 0 ; i < n ; i++ ) base.a[i][i] = 1 ; G = fast_pow( G , m ); //Matrix_print( G ) ; base = G * base ; //Matrix_print( base ) ; int ans = 0 ; for( int i = n ; i < 2 * n ; i++ ) for( int j = 0 ; j < n ; j++ ) ans += base.a[i][j] ; cout << ( ans + 1 ) % mod << endl ; } return 0; }
方法2:
[code]/* * @author FreeWifi_novicer * language : C++/C */ #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #include<queue> using namespace std; #define clr( x , y ) memset(x,y,sizeof(x)) #define cls( x ) memset(x,0,sizeof(x)) #define mp make_pair #define pb push_back typedef long long lint; typedef long long ll; typedef long long LL; const int maxn = 100 + 5 ; const int mod = 2015 ; struct Matrix { int n , m ; int a[maxn][maxn] ; Matrix( int n , int m ){ this->n = n ; this->m = m ; cls(a) ; } Matrix operator * ( const Matrix &tmp ){ Matrix res( n , tmp.m ) ; for( int i = 0 ; i < n ; i++ ){ for( int j = 0 ; j < tmp.m ; j++ ){ for( int k = 0 ; k < m ; k++ ) res.a[i][j] += a[i][k] * tmp.a[k][j] ; if( res.a[i][j] > mod ) res.a[i][j] %= mod ; } } return res ; } }; void Matrix_print( Matrix x ){ for( int i = 0 ; i < x.n ; i++ ){ for( int j = 0 ; j < x.m ; j++ ){ cout << x.a[i][j] << ' '; } cout << endl; } cout << endl ; } Matrix fast_pow( Matrix x , int n ){ Matrix res( x.n , x.m ) ; for( int i = 0 ; i < x.n ; i++ ) res.a[i][i] = 1 ; while( n ){ if( n & 1 ) res = res * x ; n >>= 1 ; x = x * x ; } return res ; } int main(){ // freopen("input.txt","r",stdin); int t ; cin >> t ; while( t-- ){ int n , m ; cin >> n >> m ; Matrix G( n + 1 , n + 1 ) ; for( int i = 0 ; i < n ; i++ ) G.a [i] = 1 ; for( int i = 0 ; i < n ; i++ ){ int k ; scanf( "%d" , &k ) ; for( int j = 0 ; j < k ; j++ ){ int tmp ; scanf( "%d" , &tmp ) ; G.a[i][tmp-1] = 1 ; } } //Matrix_print( G ) ; G = fast_pow( G , m ); //Matrix_print( G ) ; int ans = 0 ; for( int i = 0 ; i <= n ; i++ ) ans += G.a [i] ; cout << ( ans ) % mod << endl ; } return 0; }
相关文章推荐
- 怎样才能算是在技术上活跃的小公司
- Ogre源码编译教程
- 深入理解JVM内幕:从基本结构到Java 7新特性
- 单例模式
- 给未来的自己
- php serialize()与unserialize()的用法
- 线程调度实现面试题:输出ABCDABCD.....
- 如何:创建特定形状的 Windows 窗体
- hdu5407 CRB and Candies
- Android小经验:启动Eclipse,出现提示“......发现了以元素'd:skin'开头的无效内容。此处不应含有子元素...”
- php大力力 [004节]PHP常量MAMP环境下加载网页
- 题目:三数之和 II
- LeetCode "Paint House"
- HDU 5416 CRB and Tree(dfs 异或逆运算)
- [分布式java]基于JavaAPI实现消息方式的系统间通信:TCP/IP+BIO
- Clean Code(三):注释
- 题目:三数之和
- 题目:N皇后问题 II
- 很高兴加入写博客的行列,慢慢记录自己的一点点进步
- LeetCode ||Count Primes