PKU 1977 Odd Loving Bakers

题目的意思是,只有chalk的数量是奇数的Baker,才有机会成为winner,而且,成为winner的Baker才有机会按照自己的 favorite baker list,改变其他人的chalk的数量。

 

可以把开始的状态,看成是一个行向量, 且向量中的元素不是0就是1,因为题目只与奇偶性相关。

 

则在第1次celebration后,会有 B1 = B1 * A + B1 = B1 * (A + I),其中,A为转移矩阵,I为单位阵。

 

则根据 Fn+1 = Fn * (A + I) = F1 * (A + I)n的通项公式,以及二分矩阵幂的算法,可以求解。

 

#include <iostream>

#include <string.h>

using namespace std;

 

const int N = 102;

const int NAME_LENGTH = 22;

int X, n;

__int64 t;

char BakerName[N][NAME_LENGTH];

char TempName[NAME_LENGTH];

int WritePointer;

int i, j, k;

int ChalkNum, FriendList;

int BeginState[N];

int Transform[N][N];

int result[N][N];

int temp[N][N];

int EndState[N];

 

 

int find(const char *name)

{

      int i = 1;

      while(i != WritePointer)

      {

           if(!strcmp(name, BakerName[i]))

           {

                 return i;

           }

           ++i;

      }

 

      strcpy(BakerName[WritePointer++], name);

      return (WritePointer - 1);

}

 

void init()

{

      memset(BeginState, 0, sizeof(BeginState));

      memset(Transform, 0, sizeof(Transform));

      memset(EndState, 0, sizeof(EndState));

 

      memset(BakerName, 0, sizeof(BakerName));

      WritePointer = 1;

      scanf("%d %I64d", &n, &t);

      while(n--)

      {

           scanf("%s", TempName);

           int i = find(TempName);

           scanf("%d %d", &ChalkNum, &FriendList);

           BeginState[i] = ChalkNum & 1;

           while(FriendList--)

           {

                 scanf("%s", TempName);

                 j = find(TempName);

                 Transform[i][j] = 1;

           }

      }

      //转移矩阵B = A + I

      for(i = 1; i <= WritePointer - 1; ++i)

      {

           Transform[i][i] += 1;

           Transform[i][i] &= 1;

      }

      return;

}

 

void run()

{

      int n = WritePointer - 1;

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

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

      {

           result[i][i] = 1;

      }

      //因为celebration是从第次算起的

      //所以转移矩阵的乘法,应该是乘以t-1

      --t;

      while(t > 0)

      {

           if(t & 1)

           {

                 memset(temp, 0, sizeof(temp));

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

                 {

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

                      {

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

                            {

                                  if(Transform[i][k] && result[k][j])

                                  {

                                       //因为矩阵的元素不是就是

                                       //而在这个if循环内,Transform[i][k] * result[k][j] = 1

                                       //所以可以使用异或的位运算来简化计算

                                       temp[i][j] ^= Transform[i][k] * result[k][j];

                                  }

                            }

                      }

                 }

                 memcpy(result, temp, sizeof(result));

           }

 

           t = t >> 1;

           memset(temp, 0, sizeof(temp));

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

           {

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

                 {

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

                      {

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

                            {

                                  temp[i][j] ^= Transform[i][k] * Transform[k][j];

                            }

                      }

                 }

           }

           memcpy(Transform, temp, sizeof(Transform));

      }

 

      //output

      memset(EndState, 0, sizeof(EndState));

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

      {

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

           {

                 if (BeginState[j] && result[j][i])

                 {

                      EndState[i] ^= BeginState[j] * result[j][i];

                 }

           }

      }

      int winner = 0;

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

      {

           if(1 == EndState[i])

           {

                 ++winner;

           }

      }

      printf("%d/n", winner);

      return;

}

 

int main()

{

      scanf("%d", &X);

      while(X--)

      {

           init();

           run();

      }

      return 0;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值