PKU 3735 Training little cats

这道题的思想很简单,其实,就是将线性转换的关系,用一个转换矩阵来表示。

 

由于置0还有交换操作,在线性代数中,都有相应的操作相对应,见下面的3 4点

 

为了使得+1操作也有相应的操作相对应,只需要引入一只虚构的猫,使得加1的操作,就是加上最后一行

 

引入虚构的猫之后,就使得转移矩阵的大小为(n+1)*(n+1)

 

对于转移矩阵的构造,可以用如下方法:

1.初始化一个(n+1)*(n+1)的单位阵

2.对于g num1操作,使得矩阵的num1的最后一个元素加1,等价于加上最后一行,因为单位阵的最后一行是 0 0 0... 1

3.对于e num1操作,使得矩阵的num1行置0

4.对于s num1 num2操作,使得矩阵的num1行和num2行互换

 

此外,由于0<=m<=1000000000,所以,在进行多次的转换矩阵的计算时,应该使用二分法来求解矩阵乘积

 

还有,计算的结果,会超过int的范围,应该使用__int64(C++环境) 或者long long(G++环境)类型来表示

#include <iostream>

using namespace std;

const int SIZE = 103;

#define LAST (N + 1)

__int64 nuts[SIZE][SIZE];

__int64 transform[SIZE][SIZE];

__int64 result[SIZE][SIZE];//用于存放矩阵乘法的中间结果

 

__int64 M;

int N, K;

char c;

int num1, num2;

__int64 temp;

int i, j, k;

inline void init()

{

     //OJ上,不一定能够安全执行

     //可能出现run time error

     memset(transform, 0, sizeof(transform) );

     /*for(i = 1; i <= LAST; ++i)

     {

         for(j = 1; j <= LAST; ++j)

         {

              transform[i][j] = 0;

         }

     }*/

     for(i = 1; i <= LAST; ++i)

     {

         transform[i][i] = 1;

     }

     while(K--)

     {

         getchar();

         scanf("%c", &c);

         if('g' == c)

         {

              scanf("%d", &num1);

              transform[num1][LAST] += 1;

         }

         else if('s' == c)

         {

              scanf("%d %d", &num1, &num2);

              for(i = 1; i <= LAST; ++i)

              {

                   temp = transform[num1][i];

                   transform[num1][i] = transform[num2][i];

                   transform[num2][i] = temp;

              }

         }

         else

         {

              scanf("%d", &num1);

              for(i = 1; i <= LAST; ++i)

              {

                   transform[num1][i] = 0;

              }

         }

     }

     return;

}

 

inline void run()

{

     memset(nuts, 0, sizeof(nuts));

     /*for(i = 1; i <= LAST; ++i)

     {

         for(j = 1; j <= LAST; ++j)

         {

              nuts[i][j] = 0;

         }

     }*/

 

     for(i = 1; i <= LAST; ++i)

     {

         nuts[i][i] = 1;

     }

     //当输入的m为时,由于函数开头的初始化

     //结果也是正确的

     while(M > 0)

     {

         if(M & 1) //等价于1 == m % 2

         {

              memset(result, 0, sizeof(result));

              /*for(i = 1; i <= LAST; ++i)

              {

                   for(j = 1; j <= LAST; ++j)

                   {

                       result[i][j] = 0;

                   }

              }*/

 

              for(i = 1; i <= LAST; ++i)

              {

                   for(j = 1; j <= LAST; ++j)

                   {

                       for(k = 1; k <= LAST; ++k)

                       {

                            if(transform[i][k] && nuts[k][j])

                            {

                                 result[i][j] += transform[i][k] * nuts[k][j];

                            }

                       }

                   }

              }

              for(i = 1; i <= LAST; ++i)

                   for(j = 1; j <= LAST; ++j)

                   {

                       nuts[i][j] = result[i][j];

                   }

         }

 

         M = M >> 1; //等价与m = m / 2;

 

         memset(result, 0, sizeof(result));

         /*for(i = 1; i <= LAST; ++i)

         {

              for(j = 1; j <= LAST; ++j)

              {

                   result[i][j] = 0;

              }

         }*/

 

         for(i = 1; i <= LAST; ++i)

         {

              for(j = 1; j <= LAST; ++j)

              {

                   for(k = 1; k <= LAST; ++k)

                   {

                       if(transform[i][k] && transform[k][j])

                       {

                            result[i][j] += transform[i][k] * transform[k][j];

                       }

                   }

              }

         }

         for(i = 1; i <= LAST; ++i)

              for(j = 1; j <= LAST; ++j)

              {

                   transform[i][j] = result[i][j];

              }

     }

 

 

     //output

     //事实上,转移矩阵的最后一列,就是结果

     for(i = 1; i <= N; ++i)

     {

         printf("%I64d ", nuts[i][LAST]);

     }

     printf("/n");

     return;

}

 

int main()

{

     while(scanf("%d %I64d %d", &N, &M, &K) && (N + M + K))

     {

         init();

         run();

     }

     return 0;

}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值