• 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 }
  • 相关阅读:
    linux常用命令
    windows 安装elasticsearch-head插件
    spring boot 使用logback日志系统的详细说明
    mysql 修改密码的几种方式
    html跑马灯效果
    windows 安装elk日志系统
    logstash 启动报找不主类或无法加载 java
    MySQL和Postgresql的区别
    Swift-----泛型Generic
    Swift-----扩展extension
  • 原文地址:https://www.cnblogs.com/GBRgbr/p/2611989.html
Copyright © 2020-2023  润新知