{题解}[jzoj1021]【中山市选2008】矩阵

jzoj1021

Description
给出A,B,C三个01矩阵,问A*B是否等于C.
Input
本题有多组数据.
第一行的ca表示一共有ca组数据.
对于每组数据,第一行有一个整数N(1<=N<=1000)
然后就是A,B,C三个矩阵.
Output
对于每组数据,输出一行.
如果A*B=C,就输出“YES”,否则输出“NO”。

不要被矩阵乘法吓到了。
只要理解矩阵乘法就足矣

Ci,j=k=1nAi,kBk,j

二进制的话,将 乘法改为 And加法改为 Xor即可。
我们还是需要一个性质: 矩阵乘法满足交换律
于是乎,我们可以引入一个 友矩阵(大小为1*n)
之后
AB=CABF=CF

不过这个 友矩阵怎么计算呢?
全为0是有问题的,全为1也是有问题的!(可以伸出脚趾算一算)
怎么办呢?机(yi)智(ban)的,可以运用 random这个少见的小东西。
多次进行判断即可Ac。(请洗脸)

如果无聊,可以参考一下Infleaking的分治(高精度原理)
Code
正解

        maxt=5;
        maxn=100000;
var
        t,n:longint;
        i,j,l:longint;
        x,y,z,f:array[0..maxn] of longint;
        a,b,c:array[0..maxn,0..maxn] of longint;
procedure init;
var
        ch:char;
        i,j,l:longint;
begin
        readln(n);
        for i:=1 to n do
        begin
                for j:=1 to n do
                begin
                        read(ch);
                        if(ch='0')then a[i,j]:=0 else a[i,j]:=1;
                end;
                readln;
        end;
        for i:=1 to n do
        begin
                for j:=1 to n do
                begin
                        read(ch);
                        if(ch='0')then b[i,j]:=0 else b[i,j]:=1;
                end;
                readln;
        end;
        for i:=1 to n do
        begin
                for j:=1 to n do
                begin
                        read(ch);
                        if(ch='0')then c[i,j]:=0 else c[i,j]:=1;
                end;
                readln;
        end;
end;
procedure randomf;
var
        i:longint;
begin

        for i:=1 to n do f[i]:=random(2);
        fillchar(x,sizeof(x),0);
        fillchar(y,sizeof(y),0);
        fillchar(z,sizeof(z),0);
end;
procedure work;
var
        i,j,l:longint;
begin
        for i:=1 to 5 do
        begin
                randomf;
                for j:=1 to n do
                for l:=1 to n do
                y[j]:=y[j] xor (b[j,l] and f[l]);

                for j:=1 to n do
                for l:=1 to n do
                x[j]:=x[j] xor (a[j,l] and y[l]);

                for j:=1 to n do
                for l:=1 to n do
                z[j]:=z[j] xor (c[j,l] and f[l]);

                for j:=1 to n do
                if(x[j]<>z[j])then
                begin
                        writeln('NO');
                        exit;
                end;
        end;
        writeln('YES');
end;
begin
        randomize;
        readln(t);
        while t>0 do
        begin
                dec(t);
                init;
                work;
        end;
end.

Infleaking分块

const
        mo=60;
type
        col=array[0..18]of int64;
var
        i,j,k,m,n,x,y,z,q,ca:longint;
        f:int64;
        b,c:array[1..1000]of col;
        a:array[1..1000,1..1000]of longint;
        m2:array[0..60]of int64;
        x1,y1,z1:col;
        p:boolean;
        e:char;
function mul(a,b:col):col;
var
        i:longint;
begin
        for i:=0 to 18 do
        mul[i]:=a[i] and b[i];
end;
function add(a,b:col):col;
var
        i:longint;
begin
        for i:=0 to 18 do
        add[i]:=a[i] xor b[i];
end;
function xd(a,b:col):boolean;
var
        i:longint;
begin
        for i:=0 to 18 do if a[i]<>b[i] then exit(false);
        exit(true);
end;
begin
        m2[0]:=1;
        for i:=1 to 60 do m2[i]:=m2[i-1]*2;
        read(ca);
        for q:=1 to ca do
        begin
                readln(n);
                fillchar(a,sizeof(a),0);
                fillchar(b,sizeof(b),0);
                fillchar(c,sizeof(c),0);
                for i:=1 to n do
                begin
                        for j:=1 to n do
                        begin
                                read(e);
                                if e='1' then

                                a[i,j]:=1;
                        end;
                        readln;
                end;
                for i:=1 to n do
                begin
                        for j:=1 to n do
                        begin
                                read(e);
                                f:=n-j;
                                if e='1' then
                                b[i][(j-1) div mo+1]:=b[i][(j-1) div mo+1]+m2[f mod mo];
                        end;
                        readln;
                end;
                for i:=1 to n do
                begin
                        for j:=1 to n do
                        begin
                                read(e);
                                f:=n-j;
                                if e='1' then
                                c[i][(j-1) div mo+1]:=c[i][(j-1) div mo+1]+m2[f mod mo];

                        end;
                        readln;
                end;
                p:=true;
                for i:=1 to n do
                begin
                        fillchar(x1,sizeof(x1),0);
                        for j:=1 to n do
                        begin
                                if a[i,j]=1 then
                                x1:=add(x1,b[j]);
                        end;
                        if not xd(x1,c[i]) then
                        begin
                                p:=false;
                                writeln('NO');
                                break;
                        end;
                end;
                if p then writeln('YES');
        end;
end.
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于洛谷上的p1036题目,我们可以使用Python来解决。下面是一个可能的解法: ```python def dfs(nums, target, selected_nums, index, k, sum): if k == 0 and sum == target: return 1 if index >= len(nums) or k <= 0 or sum > target: return 0 count = 0 for i in range(index, len(nums)): count += dfs(nums, target, selected_nums + [nums[i]], i + 1, k - 1, sum + nums[i]) return count if __name__ == "__main__": n, k = map(int, input().split()) nums = list(map(int, input().split())) target = int(input()) print(dfs(nums, target, [], 0, k, 0)) ``` 在这个解法中,我们使用了深度优先搜索(DFS)来找到满足要求的数列。通过递归的方式,我们遍历了所有可能的数字组合,并统计满足条件的个数。 首先,我们从给定的n和k分别表示数字个数和需要取的数字个数。然后,我们输入n个数字,并将它们存储在一个列表nums中。接下来,我们输入目标值target。 在dfs函数中,我们通过迭代index来择数字,并更新取的数字个数k和当前总和sum。如果k等于0且sum等于target,我们就找到了一个满足条件的组合,返回1。如果index超出了列表长度或者k小于等于0或者sum大于target,说明当前组合不满足要求,返回0。 在循环中,我们不断递归调用dfs函数,将取的数字添加到selected_nums中,并将index和k更新为下一轮递归所需的值。最终,我们返回所有满足条件的组合个数。 最后,我们在主程序中读入输入,并调用dfs函数,并输出结果。 这是一种可能的解法,但不一定是最优解。你可以根据题目要求和测试数据进行调试和优化。希望能对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值