ZOJ 3563 Alice's Sequence II

题目链接: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 }
原文地址:https://www.cnblogs.com/GBRgbr/p/2611989.html