CCF 201512-5 矩阵 (矩阵快速幂)

问题描述
  创造一个世界只需要定义一个初状态和状态转移规则。
  宏观世界的物体运动规律始终跟物体当前的状态有关,也就是说只要知道物体足够多的状态信息,例如位置、速度等,我们就能知道物体之后任意时刻的状态。
  现在小M创造了一个简化的世界。
  这个世界中,时间是离散的,物理规律是线性的:世界的初始状态可以用一个m维向量b (0)表示,状态的转移方式用m×m的矩阵A表示。
  若已知这个世界当前的状态是b,那么下一时刻就等于b左乘状态转移矩阵A,即Ab。
  这个世界中,物体的状态也是离散的,也就是说可以用整数表示。再进一步,整数都可以用二进制编码拆分为有限位0和1。因此,这里的矩阵A和向量b的每个元素都是0或1,矩阵乘法中的加法运算视为异或运算(xor),乘法运算视为与运算(and)。
  具体地,设矩阵A第i行第j列的元素为a i , j,向量b的第i个元素为b i。那么乘法Ab所得的第k个元素为
  (a k ,1 and b 1) xor (a k ,2 and b 2) xor ⋯ xor (a k ,m and b m)
  矩阵和矩阵的乘法也有类似的表达。
  小M发现,这样的矩阵运算也有乘法结合律,例如有A(Ab)=(AA)b=A 2b。
  为了保证自己创造的世界维度不轻易下降,小M保证了矩阵A可逆,也就是说存在一个矩阵A -1,使得对任意向量d,都有A -1Ad=d。
  小M想了解自己创造的世界是否合理,他希望知道这个世界在不同时刻的状态。
  具体地,小M有n组询问,每组询问会给出一个非负整数k,小M希望你帮他求出A kb。
输入格式
  输入第一行包含一个整数m,表示矩阵和向量的规模。
  接下来m行,每行包含一个长度为m的01串,表示矩阵A。
  接下来一行,包含一个长度为m的01串,表示初始向量b (0)。(b (0)是列向量,这里表示它的转置)
  注意:01串两个相邻的数字之间均没有空格。
  接下来一行,包含一个正整数n,表示询问的个数。
  最后n行,每行包含一个非负整数k,表示询问A kb (0)
  注意:k可能为0,此时是求A 0b (0) =b (0)
输出格式
  输出n行,每行包含一个01串,表示对应询问中A kb (0)的结果。
  注意:01串两个相邻的数字之间不要输出空格。
样例输入
3
110
011
111
101
10
0
2
3
14
1
1325
6
124124
151
12312
样例输出
101
010
111
101
110
010
100
101
001
100
评测用例规模与约定
  本题使用10个评测用例来测试你的程序。
  对于评测用例1,m = 10,n = 100,k ≤ 10 3
  对于评测用例2,m = 10,n = 100,k ≤ 10 4
  对于评测用例3,m = 30,n = 100,k ≤ 10 5
  对于评测用例4,m = 180,n = 100,k ≤ 10 5
  对于评测用例5,m = 10,n = 100,k ≤ 10 9
  对于评测用例6,m = 30,n = 100,k ≤ 10 9
  对于评测用例7,m = 180,n = 100,k ≤ 10 9
  对于评测用例8,m = 600,n = 100,k ≤ 10 9
  对于评测用例9,m = 800,n = 100,k ≤ 10 9
  对于评测用例10,m = 1000,n = 100,k ≤ 10 9

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<memory.h>

using namespace std;
int A[1001][1001];
int AA[1001][1001];
int B[1001];
int ans[1001];
int res[1001][1001];
int m,n;
int temp[1001][1001];

void prt(int* a)
{
    for(int i=0;i<m;i++)
    {
        cout<<a[i];
    }
    cout<<endl;
}

int* mul(int a[][1001])
{
    //int *ans=(int*)malloc(m*sizeof(int));
    memset(ans,0,sizeof(ans));
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<m;j++)
        {
            ans[i]^=a[i][j]&B[j];
        }
    }
    return ans;
}
void mul2(int a[][1001],int b[][1001])
{
    //int res[m][m];//try one
    //int **res=(int **)malloc(m*sizeof(int*));
   // for(int i=0;i<m;i++){
    //    res[i]=(int*)malloc(m*sizeof(int));
    //}
    memset(res,0,sizeof(res));
    for(int i=0;i<m;i++){
        for(int j=0;j<m;j++){
            for(int k=0;k<m;k++){
                res[i][j]^=a[i][k]&b[k][j];
            }
        }
    }
   // return res;
}
void s_mul(int k)
{
    //int AA[1001][1001];
    //int **res;
    for(int i=0;i<m;i++){
        for(int j=0;j<m;j++){
            if(i==j) temp[i][j]=1;
            else temp[i][j]=0;
        }
    }
    for(int i=0;i<m;i++){
        for(int j=0;j<m;j++){
            AA[i][j]=A[i][j];
        }
    }
    /*for(int i=0;i<m;i++){
        for(int j=0;j<m;j++){
            cout<<AA[i][j]<<" ";
        }
        cout<<endl;
    }*/
    while(k)
    {
        if(k&1){
            mul2(temp,AA);
            for(int i=0;i<m;i++){
                for(int j=0;j<m;j++){
                    temp[i][j]=res[i][j];
                }
            }
          /*  for(int i=0;i<m;i++){
              for(int j=0;j<m;j++){
                cout<<AA[i][j]<<" ";
            }
            cout<<endl;
        }*/
        }
        k=k>>1;
        mul2(AA,AA);
        for(int i=0;i<m;i++){
            for(int j=0;j<m;j++){
                AA[i][j]=res[i][j];
            }
        }
        /*for(int i=0;i<m;i++){
            for(int j=0;j<m;j++){
                cout<<AA[i][j]<<" ";
            }
            cout<<endl;
        }*/
    }
}
int main()
{
    cin>>m;
    getchar();
    for(int i=0;i<m;i++){
        for(int j=0;j<m;j++){
            char c;
            c=getchar();
            A[i][j]=c-'0';
        }
        getchar();
    }
    /*for(int i=0;i<m;i++){
        for(int j=0;j<m;j++){
            cout<<A[i][j]<<" ";
        }
        cout<<endl;
    }*/
    for(int i=0;i<m;i++){
        char c;
        c=getchar();
        B[i]=c-'0';
    }
    cin>>n;
    while(n--)
    {
        int k=0;
        cin>>k;
        if(k==0)
        {
            prt(B);
        }
        else{
            s_mul(k);
            mul(temp);
            prt(ans);
        }

    }
}





  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值