【2016 泉市教科】保险箱

本文介绍了一种基于矩阵的身份认证系统,该系统通过识别个人独有的n*n矩阵特征来进行身份验证。文章探讨了如何通过数学方法计算不同矩阵组合的数量,并提供了解决方案的Pascal代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

保险箱

问题描述

  小 A 轻松地解开了密码锁,获得了神秘宝物(你们猜啊就不告诉你们是什么)。他将宝物藏在了自己和小 B 共同拥有的保险箱里。它有一套小 A 开发的通用而机智的身份认证系统,这套系统将利用传感器将每个人识别为一个不变的电子认证特征:一个 n*n 的矩阵。其中,矩阵的每行每列都有两个点。这一身份认证系统会利用玄学算法求出这一矩阵,并且对此进行解析。由于每个人的特征都是独一无二的矩阵,系统可以快速地认证出身份,简单、快
捷、方便。
  但是小 A 显然不希望别人和他破解密码锁那样轻松地解开这一身份认证系统,于是他不断地修改着自己做识别的玄学算法,使其更加完备。他发现对于一个矩阵,只要其他人识别出的特征矩阵不与之“相似”,身份认证信息的错误率会降低很多,也更不容易被欺骗。经过多次实验,他发现 a 与 b“相似”意味着:矩阵 a 通过任意次行列变换可以变成矩阵 b。
  
例如下面的例子中,对于 3*3 的矩阵,其中矩阵 a 与矩阵 b 被视为“相似”矩阵

  小 A 想知道对于一个 n,可以有多少种不“重复”的 n*n 矩阵。为了让题目更水,你只需要输出答案 mod 10 8 +7 的值就可以了。

输入

  输入文件名为 safe.in。
  第一行,一个整数 T。表示数据组数。
  接下来 T 行,每行一个整数 n。表示一组数据。

输出

  输出文件名为 safe.out。
  T 行,每行一个整数,表示方案数。由于答案可能很大,只需要输出 mod 10 8 +7 的值。

Sample Input

3
2
3
4

Sample Output

1
1
2

样例解释


属于同一种方案。

数据范围

  对于 10%的数据,N≤5。
  对于 50%的数据,N≤150。
  对于 100%的数据,T≤5,N≤2×10^3 。

题解

  10%的数据范围,我们可以采用打表的形式求解,题目样例中已经给出了大部分0~5的答案,这算是一种快速得分的办法。
  对于50%~100%的数据范围,需要将题目联想成一张二分图。二分图的两侧分别为图中点的X、Y轴,二分图中的连线则代表了一个图中的点。联想到二分图之后,我们来观察本题的性质:矩阵的每行每列都有两个点。这个地方可以告诉我们,在本题里,转换成二分图之后,二分图里至少会有一个环(证明:若二分图中无环,则该二分图的长度将会变成无限长),而多少个环,以及环的大小,就是这个二分图的种类。图中行、列变换是可以理解为在环内的数字移动而已,环中的连线不会改变,那由此想出的解法是自然数拆分。
  而自然数拆分又要考虑一些边界情况,环不能是由一组X、Y组成,必定至少由两组X、Y组成,所以自然数不能拆分成含1的情况,那这里由动态转移方程得出
  附上Pascal代码:
  


program safe;
var f:Array[0..5000,0..5000] of longint;
    ck:array[0..5000,0..5000] of boolean;
    i,j,t,n,k:longint;
const mo=100000007;


function cal(u,v:longint):longint;
var tmp:longint;
begin

   if (ck[u,v]) then exit(f[u,v]);
   ck[u,v]:=true;
   if (u=1) or (v = 1) then begin f[u,v]:=0;exit(f[u,v]);end;
   if u=0 then begin f[u,v]:=1;exit(1);end;
   if v=2 then
   begin
      tmp:=(u mod 2);
      if tmp=0 then f[u,v]:=1 else f[u,v]:=0;
      exit(f[u,v]);end;
   if u<v then begin f[u,v]:=cal(u,u);exit(f[u,v]);end;
   f[u,v]:=(cal(u-v,v) + cal(u,v-1)) mod mo;
   exit(f[u,v]);
end;


begin
   assign(input,'safe.in') ;reset(input);
   assign(output,'safe.out');rewrite(output);
read(t);
  for i:=1 to t do
  begin
     fillchar(ck,sizeof(ck),false);
     read(n);
     writeln(cal(n,n));

  end;
     close(input);close(output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值