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 }

你可能感兴趣的:(sequence)