HDU 2276 & FZU 1692 (矩阵快速幂+循环同构优化)
2015-08-16 22:26
543 查看
HDU 2276
题意:
给定一个01**字符串环**(2<=字符串长度<=100)然后进行m次的变换。定义变换的规则为:如果当前位置i的左边是1(下标为0的左边是n-1),那么i就要改变状态0->1 , 1->0
比如当前的状态为100101那么一秒过后的状态为010111。
思路:
用公式表示变化状态其实就是:ai=(a(i+n−1)%n+ai)%2a_i = (a_{(i+n-1)\%n}+a_i)\%2
换成位操作就是:
ai=a(i+n−1)%na_i = a_{(i+n-1)\%n}^ aia_i
于是我们可以建立一个变化矩阵:
⎛⎝⎜⎜⎜⎜⎜⎜⎜⎜1100...00110...00011...00001...0..................0000...11000...1⎞⎠⎟⎟⎟⎟⎟⎟⎟⎟∗⎛⎝⎜⎜⎜⎜⎜⎜⎜⎜a0a1a2a3...an−1⎞⎠⎟⎟⎟⎟⎟⎟⎟⎟\left(
\begin{array}{ccc}
1&0&0&0&...&0&1\\
1&1&0&0&...&0&0\\
0&1&1&0&...&0&0\\
0&0&1&1&...&0&0\\
...&...&...&...&...&...&...\\
0&0&0&0&...&1&1\\
\end{array}
\right)
*
\left(
\begin{array}{ccc}
a_0\\
a_1\\
a_2\\
a_3\\
...\\
a_{n-1}\\
\end{array}
\right)
左边是变换矩阵,右边是原序列,相乘一次后输出结果即是变换一次后序列。
然后快速幂就搞定啦~
ps.把矩阵乘法里的*改&,+改^可以快很多
pps.由于变换矩阵是循环同构的,可以求出第一行推出其他行,能从O(n3)O(n^3)降至O(n2)O(n^2),然而这题O(n3)O(n^3)也就这么水过去了,但下一题就没那么好运了..
代码君:
[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 = 105; const int mod = 2; lint n; 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] = res.a[i][j] ^ (a[i][k] & tmp.a[k][j]); 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 , lint 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; x = x*x; n >>= 1; } return res; } void solve(string s , lint n){ int l = s.length(); Matrix fun(l,l); Matrix base(l,1); for(int i = 0 ; i < l - 1; i++) fun.a[i][i] = fun.a[i][i+1] = 1; fun.a[l-1][0] = fun.a[l-1][l-1] = 1; //Matrix_print(fun); for(int i = 0 ; i < l; i++) base.a[i][0] = s[i] - '0'; fun = fast_pow(fun , n); base = fun*base; for(int i = 0 ; i < l ; i++) cout << base.a[(i - n%l + l)%l][0]; puts(""); } int main(){ //freopen("input.txt","r",stdin); string s; lint n ; while(cin >> n >> s){ solve(s,n); } return 0; }
FZU 1692
题意:
类似上一题,n个小朋友围成一个环(2<=n<=100)然后进行m次的游戏。
一开始,第i个小朋友有AiA_i个苹果。
定义游戏的规则为:每一次游戏处于i位置的小朋友获得R∗A(i+n−1)%n+L∗A(i+1)%nR*A_{(i+n-1)\%n}+L*A_{(i+1)\%n}个苹果(题目有误。。大坑啊!!)
求m次游戏后每个小朋友的苹果数量。
思路:
凑样例愣是凑了半小时不明所以然,所幸搜了题解后被告知题目有误。变化矩阵如下:
⎛⎝⎜⎜⎜⎜⎜⎜⎜⎜1R00...LL1R0...00L1R...000L1...0..................0000...RR000...1⎞⎠⎟⎟⎟⎟⎟⎟⎟⎟∗⎛⎝⎜⎜⎜⎜⎜⎜⎜⎜A0A1A2A3...An−1⎞⎠⎟⎟⎟⎟⎟⎟⎟⎟\left(
\begin{array}{ccc}
1&L&0&0&...&0&R\\
R&1&L&0&...&0&0\\
0&R&1&L&...&0&0\\
0&0&R&1&...&0&0\\
...&...&...&...&...&...&...\\
L&0&0&0&...&R&1\\
\end{array}
\right)
*
\left(
\begin{array}{ccc}
A_0\\
A_1\\
A_2\\
A_3\\
...\\
A_{n-1}\\
\end{array}
\right)
这题的trick点其实还是循环同构矩阵的乘法优化,通过求出第一行矩阵得到其他行,不这么做必吃TLE,谨记谨记。
代码君:
[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; lint n1 , m1 , L , R , M; lint A[maxn]; struct Matrix{ int n , m ; lint 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 < tmp.m ; i++ ) for( int j = 0 ; j < m ; j++ ) res.a[0][i] = ( res.a[0][i] + ( a[0][j] * tmp.a[j][i] ) % M ) % M; for( int i = 1 ; i < n ; i++ ) for( int j = 0 ; j < m ; j++ ) res.a[i][j] = res.a[i - 1][( j - 1 + n ) % n]; return res; } }; void Matrix_input( Matrix x ){ for( int i = 0 ; i < x.n ; i++ ){ for( int j = 0 ; j < x.m ; j++ ){ cout << x.a[i][j] << ' '; } puts(""); } puts(""); } Matrix fast_pow( Matrix x , lint 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; x = x * x ; n >>= 1; } return res; } void input(){ cin >> n1 >> m1 >> L >> R >> M; for( int i = 0 ; i < n1 ; i++ ){ scanf( "%I64d" , &A[i] ); } } void solve(){ if( m1 == 0 ) { for( int i = 0 ; i < n1 ; i++ ){ if( i ) printf( " " ); printf( "%I64d" , A[i] % M); } puts(""); return; } Matrix fun( n1 , n1 ); for( int i = 0 ; i < n1 ; i++ ){ fun.a[i][( i + 1 ) % n1] = L; fun.a[i][( i - 1 + n1 ) % n1] = R; fun.a[i][i] = 1; } //Matrix_input( fun ); fun = fast_pow( fun , m1 ); //Matrix_input( fun ); for( int i = 0 ; i < n1 ; i++ ){ lint sum = 0 ; for( int j = 0 ; j < n1 ; j++ ) sum = ( sum + fun.a[i][j] * A[j] % M ) % M; if( i ) printf( " " ); printf( "%I64d" , sum ); } puts(""); } int main(){ //freopen("input.txt","r",stdin); int t ; cin >> t; while( t-- ){ input(); solve(); } return 0; }
相关文章推荐
- [线段树]hdu5316
- SpringMVC+MyBatis整合(3)特别篇SpringMVC配置
- ArrayAdapter的使用
- python使用libssh2连接linux
- 项目实战之玩转div+css制作自定义形状
- 在Ubuntu上配置django环境系统架构命令
- vijos - P1286座位安排 (DP状态压缩 + 组合数 + python)
- 从docker-hub和docker-registry看优秀的后端服务设计实现
- postgresql 9.4.4 安装
- java基础-面向对象概述
- PCA-Principal Components Analysis数学原理
- python使用libssh2连接linux
- 坚持写东西
- 剑指offer——面试题22:栈的压入、弹出序列
- 黑马程序员——Java基础--集合框架(2)
- 【leetcode】Add Digits【java】
- 命运的安排
- python xpath
- 剑指offer:合并两个排序的链表
- Linux/unix 配置java环境变量