快速幂和矩阵快速幂

目录

1.快速幂模板

 2.RSA解密      2019年省赛

 3.矩阵相乘

 4.矩阵快速幂

 5.垒骰子  2015年省赛


1.快速幂模板

题目描述

输入 bpk 的值,求 b^p \mod k的值。其中 bpk 为 int64 数。

输入描述

三个整数 b,p,k

输入描述

输出 b^p \mod k=s,s 为运算结果。

样例输入

2 10 

样例输出

7

def fastPow(a,n,mod):
    ret = 1
    while n:
        if(n&1):
             ret = ret*a % mod
        a = a*a % mod
        n>>=1
    return ret

a,n,p = map(int, input().split())
print(fastPow(a,n,p))

 2.RSA解密      2019年省赛

题目描述

RSA 是一种经典的加密算法。它的基本加密过程如下。

首先生成两个质数 p,q,令 n=pq,设 d 与 (p−1)⋅(q−1) 互质,则可找到 e 使得 de 除 (p−1)⋅(q−1) 的余数为 1。

n,d,e 组成了私钥,n,d 组成了公钥。

当使用公钥加密一个整数 X 时(小于 n),计算 C = X^d\ mod\ n,则 C 是加密后的密文。

当收到密文 C 时,可使用私钥解开,计算公式为X = C^e\ mod n

例如,当 p = 5, q = 11, d = 3时,n = 55 e = 27。

若加密数字 24,得24^3\ mod\ 55 = 19 解密数字 19,得 19^{27}\ mod\ 55 = 24

现在你知道公钥中 n = 1001733993063167141, d = 212353,同时你截获了别人发送的密文 C = 20190324,请问,原文是多少?

1.求p,q

因为p,q是质数,所以n只有这两个因子

from math import *
n = 1001733993063167141
k = int(sqrt(n))
for i in range(2,k):
   if n%i == 0:
      print(i,n//i)

p=891234941、q=1123984201。

2.求e

d*e/(p-1)*(q-1)=k·····1

n = 1001733993063167141
d = 212353
p=891234941
q=1123984201
tmp = (p - 1) * (q - 1)
print(tmp)
for i in range(2,n+1):
    now = i * tmp + 1
    if (now % d == 0):
           print(now // d)   #打印e
           break             #有很多e,求第一个就行了

3.X = C^e \mod n

def fastPow(a,b,mod):
    ret = 1
    while b:
        if(b&1):
             ret = ret*a % mod
        a = a*a % mod
        b>>=1
    return ret
 
n = 1001733993063167141
e = 823816093931522017   #试试其他的e
C = 20190324
print(fastPow(C,e,n))        #579706994112328949

 3.矩阵相乘

题目描述

小明最近刚刚学习了矩阵乘法,但是他计算的速度太慢,于是他希望你能帮他写一个矩阵乘法的运算器。

输入描述

输入的第一行包含三个正整数 N,M,K,表示一个 $NM的矩阵乘以一个的矩阵乘以一个MK$ 的矩阵。

接下来 N 行,每行 M 个整数,表示第一个矩阵。再接下来的 M 行,每行 K 个整数,表示第二个矩阵。

0<N,M,K≤100, 0≤ 矩阵中的每个数≤1000。

输入描述

输出有 N 行,每行 K 个整数,表示矩阵乘法的结果。

样例输入

2 1 3
1
2
1 2 3

样例输出

1 2 3
2 4 6
A=[]
B=[]
C=[[0 for i in range(101)]for j in range(101)]
n,m,a=map(int,input().split())
for i in range(n):
    A.append(list(map(int,input().split())))
for j in range(m):
    B.append(list(map(int,input().split())))
for i in range(n):
    for j in range(a):
        for k in range(m):
            C[i][j]+=A[i][k]*B[k][j]
for i in range(n):
    for j in range(a):
        print(C[i][j],end=' ')
    print()

 4.矩阵快速幂

题目描述

给定一个 N 阶矩阵 A 和一个常数 M,请你输出 A 的 M 次幂。

输入描述

输入第一行包含两个整数 N,M

接下来 N 行,每行包含 N 个数,表示矩阵 A

1≤N≤30,0≤M≤5,0≤ 矩阵中的每个数 ≤5。

输入描述

输出有 N 行,每行 N 个整数,表示 A^M

样例输入

2 2
1 2
3 4

样例输出

7 10
15 22
def multi(A,B):
     n=len(A)
     C=[[0 for i in range(n)]for j in range(n)]
     for i in range(n):
          for k in range(n):
               for j in range(n):
                    C[i][j]+=A[i][k]*B[k][j]
     return C
def power(A, n):
    N = len(A)
    res = [[0] * N for i in range(N)]
    for i in range(N): 
        res[i][i] = 1
    while n:
        if n &1:
            res = multi(res, A)
        A = multi(A, A)
        n>>= 1
    return res
n,m=map(int,input().split())
A=[]
for i in range(n):
     A.append(list(map(int,input().split())))
li=power(A,m)
for i in range(n):
     for j in range(n):
          print(li[i][j],end=' ')
     print()

 5.垒骰子  2015年省赛

题目描述

赌圣 atm 晚年迷恋上了垒骰子,就是把骰子一个垒在另一个上边,不能歪歪扭扭,要垒成方柱体。

经过长期观察,atm 发现了稳定骰子的奥秘:有些数字的面贴着会互相排斥!

我们先来规范一下骰子:1 的对面是 4,2 的对面是 5,3 的对面是 6。

假设有 m 组互斥现象,每组中的那两个数字的面紧贴在一起,骰子就不能稳定的垒起来。

atm 想计算一下有多少种不同的可能的垒骰子方式。

两种垒骰子方式相同,当且仅当这两种方式中对应高度的骰子的对应数字的朝向都相同。

由于方案数可能过多,请输出模 10^9 + 7的结果。

不要小看了 atm 的骰子数量哦~

输入描述

输入第一行两个整数 n,mn 表示骰子数目;

接下来 m 行,每行两个整数 a,b ,表示 a 和 b 数字不能紧贴在一起。

其中,0 < n \leq 10^9, m \leq 36

输入描述

输出一行一个数,表示答案模 10^9+7的结果。

样例输入

2 1
1 2

样例输出

544

 我们先不考虑互斥问题,推理一下有多少种方案:

  1. 1个骰子的情况。一个骰子有 6 个面,每个面朝上的时候侧面都可以旋转得到 4 个不同的摆放结果,共有 4×6=24 种。
  2. 2 个骰子的情况。一上一下两个骰子,共有(4×6)×(4×6)=576 种
  • 1 个骰子的 6 个面的总方案=\begin{bmatrix} 4\\4\\4\\4\\4\\4 \end{bmatrix} 6 个面,每个面 4 种方案,共 4×6=24 种。

  • 从 1 个骰子到 2 个骰子,乘以一个转移矩阵:

    垒 2 个骰子的方案 = \begin{bmatrix} 4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \end{bmatrix} \times \begin{bmatrix} 4\\4\\4\\4\\4\\4 \end{bmatrix}​,共 (4×6) × (4×6)=576种。

  • 垒 3 个骰子的方案 == \begin{bmatrix} 4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \end{bmatrix} \times\begin{bmatrix} 4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \\4 & 4 & 4 & 4 & 4 & 4 \end{bmatrix} \times \begin{bmatrix} 4\\4\\4\\4\\4\\4 \end{bmatrix}

大佬:这样就转换成了矩阵乘法。垒 n 个骰子,等于 n−1 个转移矩阵相乘,最后再乘以第 1 个骰子。不过如果加上互斥,就需要排除一些情况,即把转移矩阵中互斥的位置置为 0。

import math

mod = int(math.pow(10,9))+7

def multi(A, B):    #矩阵乘法
    C = [[0]*6 for i in range(6)]
    for i in range(6):
      for j in range(6):
         for k in range(6):
            C[i][j] = int((C[i][j] + A[i][k] * B[k][j]) % mod)
    return C

def power(A, n):    #矩阵快速幂
    res = [[0]*6 for i in range(6)]
    for i in range(6):
        res[i][i] = 1
    while n:
        if n % 2:
            res = multi(res, A)
        A = multi(A, A)
        n >>= 1
    return res

def solve(n, dice):
    transfer = [[4]*6 for i in range(6)]  #转移矩阵
    for i in range(6):                  #去掉互斥的情况
        for j in dice.get((i+3)%6,[]):  #0对面是3,1对4,2对5
            transfer[i][j]= 0
    transfer = power(transfer, n-1)     #转移矩阵乘n-1次
    temp = [4]*6                        #表示最下面的骰子
    ans = [0]*6
    for i in range(6):                  #最后乘最下面的骰子
        for j in range(6):
            ans[i] += transfer[i][j] * temp[j]
    print(int(sum(ans) % mod))

n, m = [int(str) for str in input().split()]
dice = dict()                  #用字典记录互相排斥的面
for i in range(m):
   x, y = [int(str)-1 for str in input().split()]
   if x not in dice:   dice[x] = [y]
   else:               dice[x].append(y)
   if y not in dice:   dice[y] = [x]
   else:               dice[y].append(x)
solve(n, dice)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值