题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4562
题目:给出一组数列和六种操作, 输出经过P次操作之后的数列。
分析:因为 P (1≤ P ≤ 109)很大,所以直接模拟会超时。也是看了解题报告之后才知道要用矩阵快速幂做。
首先,把操作转化为矩阵乘法。
因为 1×n 的矩阵乘以 n×n 的矩阵还是得到一个 1×n 的矩阵,所以对数列的每一种操作都可以描述成一个n×n 的矩阵。
然后再用矩阵快速幂得结果即可。
快速幂模板:http://www.2cto.com/kf/201207/140412.html
1 #include <cstdio> 2 #include <cstring> 3 4 const int MAXN = 30; 5 const int MOD = 10000007; 6 7 struct oper_Mat 8 { 9 long long int Mat[MAXN][MAXN]; 10 friend oper_Mat operator*( oper_Mat &a, oper_Mat&b ); 11 friend oper_Mat operator^( oper_Mat a, long long int b ); 12 }; 13 14 oper_Mat OP[12]; 15 oper_Mat initial; 16 int n; 17 18 oper_Mat operator*( oper_Mat &a, oper_Mat &b ) //矩阵乘法 19 { 20 oper_Mat temp; 21 22 memset( temp.Mat, 0, sizeof(temp.Mat) ); 23 24 for ( int i = 1; i <= n; i++ ) 25 for ( int j = 1; j <= n; j++ ) 26 { 27 temp.Mat[i][j] = 0; 28 for ( int k = 1; k <= n; k++ ) 29 temp.Mat[i][j] = (temp.Mat[i][j] + (a.Mat[i][k] * b.Mat[k][j]) % MOD ) % MOD; 30 } 31 32 return temp; 33 } 34 35 oper_Mat operator^( oper_Mat a, int k ) //二进制矩阵快速幂 36 { 37 oper_Mat unit; 38 39 memset( unit.Mat, 0, sizeof(unit.Mat) ); 40 for ( int i = 0; i < MAXN; i++ ) 41 unit.Mat[i][i] = 1; 42 43 while ( k ) 44 { 45 if ( k&1 ) unit = unit * a; 46 a = a * a; 47 k >>= 1; 48 } 49 50 return unit; 51 } 52 53 void init( int x ) //初始化为单位阵 54 { 55 memset( OP[x].Mat, 0, sizeof(OP[x].Mat) ); 56 57 for ( int i = 1; i <= n; i++ ) 58 OP[x].Mat[i][i] = 1; 59 60 return; 61 } 62 63 void remove( int x ) 64 { 65 int i; 66 scanf( "%d", &i ); 67 68 init(x); 69 70 OP[x].Mat[i][i] = 0; 71 72 return; 73 } 74 75 void Double( int x ) 76 { 77 int i; 78 scanf( "%d", &i ); 79 80 init(x); 81 82 OP[x].Mat[i][i] = 2; 83 84 return; 85 } 86 87 void add( int x ) 88 { 89 int i, j; 90 scanf( "%d%d", &i, &j ); 91 92 init(x); 93 94 if ( i == j ) 95 OP[x].Mat[i][i] = 2; 96 else 97 OP[x].Mat[j][i] = 1; 98 99 return; 100 } 101 102 void swap( int x ) 103 { 104 int i, j; 105 scanf( "%d%d", &i, &j ); 106 107 init(x); 108 109 OP[x].Mat[i][i] = 0; 110 OP[x].Mat[j][j] = 0; 111 112 OP[x].Mat[i][j] = 1; 113 OP[x].Mat[j][i] = 1; 114 115 return; 116 } 117 118 void invert( int x ) 119 { 120 int i, j; 121 scanf("%d%d", &i, &j); 122 123 init(x); 124 125 for ( int m = i; m <= j; m++ ) 126 OP[x].Mat[m][m] = 0; 127 128 for ( int m = i, nn = j; m <= j; m++, nn-- ) 129 OP[x].Mat[ nn ][ m ] = 1; 130 131 return; 132 } 133 134 void transform( int x ) 135 { 136 int c, i, d, j; 137 scanf( "%d%d%d%d", &c, &i, &d, &j ); 138 139 init(x); 140 141 OP[x].Mat[i][i] = c; 142 OP[x].Mat[j][i] = d; 143 144 OP[x].Mat[j][j] = 0; 145 146 return; 147 } 148 149 int main() 150 { 151 // freopen( "out.out", "w", stdout ); 152 while ( scanf("%d", &n) != EOF ) 153 { 154 for ( int i = 1; i <= n; i++ ) 155 scanf("%lld", &initial.Mat[1][i]); 156 157 int m; 158 scanf( "%d", &m ); 159 char str[30]; 160 for ( int i = 1; i <= m; i++ ) 161 { 162 scanf( "%s", str ); 163 switch( str[0] ) 164 { 165 case 'r' : 166 remove(i); 167 break; 168 case 'd' : 169 Double(i); 170 break; 171 case 'a' : 172 add(i); 173 break; 174 case 's' : 175 swap(i); 176 break; 177 case 'i' : 178 invert(i); 179 break; 180 case 't' : 181 transform(i); 182 break; 183 } 184 } 185 186 oper_Mat ans; 187 188 memset( ans.Mat, 0, sizeof(ans.Mat) ); 189 for ( int i = 0; i < MAXN; i++ ) 190 ans.Mat[i][i] = 1; 191 192 for ( int i = 1; i <= m; i++ ) 193 ans = ans * OP[i]; 194 195 int step; 196 scanf( "%d", &step ); 197 198 int k = step / m; 199 int Mod = step % m; 200 201 ans = ans ^ k; 202 203 for ( int i = 1; i <= Mod; i++ ) 204 ans = ans * OP[i]; 205 206 ans =initial*ans; 207 208 printf( "%lld", ans.Mat[1][1] ); 209 for ( int i = 2; i <= n; i++ ) 210 printf(" %lld", ans.Mat[1][i]); 211 putchar('\n'); 212 } 213 214 return 0; 215 }