【蓝桥杯python研究生组备赛】004 数论

题目1 等差数列

数学老师给小明出了一道等差数列求和的题目。

但是粗心的小明忘记了一部分的数列,只记得其中 N 个整数。

现在给出这 N 个整数,小明想知道包含这 N 个整数的最短的等差数列有几项?

输入格式

输入的第一行包含一个整数 N。

第二行包含 N 个整数 A1,A2,···,AN。(注意 A1∼AN 并不一定是按等差数
列中的顺序给出)

输出格式

输出一个整数表示答案。

数据范围

2≤N≤100000,
0≤Ai≤109

输入样例:
5
2 6 4 10 20
输出样例:
10
解题思路

蓝桥杯笔记:蓝桥杯备赛笔记

a,a+2d,a+3d,a+89d……

长度 = m a x − m i n d + 1 长度=\frac{max-min}{d}+1 长度=dmaxmin+1

使得长度最短,max和min已经固定,那么只能使得d最大。
即需要找到每个元素减去第一个元素差 之间的最大公约数

from math import gcd

n=int(input())

data=list(map(int,input().split()))
data.sort()
d=0
for i in range(n):
    d=gcd(d,data[i]-data[0])

if d==0:
    print(n)
else:
    ans=(data[-1]-data[0])//d+1
    print(ans)

知识点

  1. 0和自然数的最大公约数,还是该自然数
  2. gcd原理为辗转相除法:
    def gcd(a,b):
        if b==0:
            return a
        return gcd(b,a%b)
    print(gcd(8,4))
    

题目2 X的因子链

输入正整数 X,求 X 的大于 1 的因子组成的满足任意前一项都能整除后一项的严格递增序列的最大长度,以及满足最大长度的序列的个数。

输入格式

输入包含多组数据,每组数据占一行,包含一个正整数表示 X。

输出格式

对于每组数据,输出序列的最大长度以及满足最大长度的序列的个数。

每个结果占一行。

数据范围

1<X≤220

输入样例:
2
3
4
10
100
输出样例:
1 1
1 1
2 1
2 2
4 6

思路

主要是用到了几个数论知识:

  1. 线性筛素数,时间复杂度o(n)

  2. 筛素数的同时,求得每个数的最小质数约数,比如100的最小质数约数是2

  3. 任何一个数一定能得到以下形式(算数基本定理):
    n = p 1 c 1 ∗ p 2 c 2 ∗ p n c n n=p_1^{c1}*p_2^{c2}*p_n^{cn} n=p1c1p2c2pncn,其中 p 1 , … , p n p_1,\dots,p_n p1,,pn均为质数,比如 100 = 2 2 ∗ 5 2 100=2^{2}*5^{2} 100=2252,序列的最大长度就是4

  4. 而这4个质约数的排列方案为: ( c 1 + c 2 + … … + c n ) ! c 1 ! ∗ c 2 ! ∗ … … ∗ c n ! \frac{(c1+c2+……+cn)!}{c1!*c2!*……*cn!} c1!c2!……cn!(c1+c2+……+cn)!
    比如:2255,2255这算一种方案,最终方案是全排列/每个重复的质约数内部的排列
    更多知识点:蓝桥杯备赛笔记

python代码

def get_primes(n):
    st=[True]*(n+1)
    st[0]=st[1]=False
    primes=[]
    minp=[0]*(n+1)
    minp[1]=1
    
    for i in range(2,n+1):
        if st[i]:
            primes.append(i)
            minp[i]=i
        for p in primes:
            if i*p>n:
                break
            st[i*p]=False
            minp[i*p]=p
            if i%p==0:
                break
    return primes,minp

N=2**20+1
primes,minp=get_primes(N)
while True:
    try:
        x=int(input().strip())
        
        total=0#大于1的质数约数个数
        sum1=[0]*(100)#对应的质数约数个数
        index=[]
        num=0#第几个质数
        while x>1:
            i=minp[x]
            index.append(i)
            while x%i==0:
                x//=i
                sum1[num]+=1
                total+=1
            num+=1
        index=list(set(index))
        ans=1
        for i in range(1,total+1):
            ans*=i
        for j in range(len(index)):
            for k in range(1,sum1[j]+1):
                ans//=k
        print(total,ans)
   
    except EOFError:
        break

知识点

  1. 线性筛法,同时得到最小质约数
  2. 对列表进行去重:a=list(set(a))
  3. 一开始我是对每一个数求最小约数,这样计算量会太大,而且确实求一次最大的数字放在列表即可

题目3 五指山

大圣在佛祖的手掌中。

我们假设佛祖的手掌是一个圆圈,圆圈的长为 n,逆时针记为:0,1,2,…,n−1,而大圣每次飞的距离为 d。

现在大圣所在的位置记为 x,而大圣想去的地方在 y。

要你告诉大圣至少要飞多少次才能到达目的地。

注意:孙悟空的筋斗云只沿着逆时针方向翻。

输入格式

有多组测试数据。

第一行是一个正整数 T,表示测试数据的组数;

每组测试数据包括一行,四个非负整数,分别为如来手掌圆圈的长度 n,筋斗所能飞的距离 d,大圣的初始位置 x 和大圣想去的地方 y。

输出格式

对于每组测试数据,输出一行,给出大圣最少要翻多少个筋斗云才能到达目的地。

如果无论翻多少个筋斗云也不能到达,输出 Impossible。

数据范围

1≤T≤5,
2<n<109,
0<d<n,
0≤x,y<n

输入样例:
2
3 2 0 2
3 2 0 1
输出样例:
1
2

思路

  1. 扩展欧几里得算法,得到ax+by=gcd(a,b)的一组解,且所有的解的形式都能表示为:
    x = x 0 + k ∗ b g c d ( a , b ) , y = y 0 − k ∗ a g c d ( a , b ) x=x_0+k*\frac{b}{gcd(a,b)},y=y_0-k*\frac{a}{gcd(a,b)} x=x0+kgcd(a,b)b,y=y0kgcd(a,b)a
  2. 并且最小的非负解: x 0 % b g c d ( a , b ) x_0 \%\frac{b}{gcd(a,b)} x0%gcd(a,b)b , y 0 % a g c d ( a , b ) y_0\%\frac{a}{gcd(a,b)} y0%gcd(a,b)a
  3. 本题转化模型过程为:
    定义b为筋斗云次数,a为一个数字
    则题意转化为:
    x + b d = y + a n x+bd=y+an x+bd=y+an
    − a n + b d = y − x -an+bd=y-x an+bd=yx

那么我们利用扩展欧几里得算法得到的等式为 − a n + b d = g c d ( n , d ) -an+bd=gcd(n,d) an+bd=gcd(n,d)
此时需要判断:

  1. y-x是不是gcd(n,d)的整数倍
  2. 若不是整数倍,那么输出Impossible
  3. 若是整数倍,那么相应的把等式转化: − a n + b d = g c d ( n , d ) -an+bd=gcd(n,d) an+bd=gcd(n,d)➡️ − a n + b d = y − x -an+bd=y-x an+bd=yx

最后,需要找到最小的b

python代码

def exgcd(a,b):
    if b==0:
        return a,1,0
    else:
        d,x1,y1=exgcd(b,a%b)
        x=y1
        y=x1-(a//b)*y1
        return d,x,y

t=int(input())
for i in range(t):
    
    n,d,x,y=map(int,input().split())
    gcd,a,b=exgcd(n,d)

    if (y-x)%gcd!=0:
        print('Impossible')
    else:
        b*=(y-x)//gcd#进行相应的转化
        n//=gcd
        print(b%n)

知识点

  1. 扩展欧几里得推导过程:
    a x + b y = d ( 1 ) ax+by=d (1) ax+by=d(1),现在假设一组递归函数返回的解是 b x 1 + a % b y 1 = g c d ( b , a % b ) ( 2 ) b{x_1}+a\%b {y_1}=gcd(b,a\%b)(2) bx1+a%by1=gcd(b,a%b)(2)
    a%b=a-a//b*b,代入(2), b x 1 + ( a − a / / b ∗ b ) y 1 = g c d ( b , a % b ) b{x_1}+(a-a//b*b){y_1}=gcd(b,a\%b) bx1+(aa//bb)y1=gcd(b,a%b)
    对比(1), x = y 1 , y = x 1 − ( a / / b ) y 1 x=y_1,y=x_1-(a//b)y_{1} x=y1,y=x1(a//b)y1

  2. 蓝桥杯备赛笔记

题目4 C循环

对于 C 语言的循环语句,形如:

for(variable = A; variable != B; variable += C)
  statement;

请问在 k 位存储系统中循环几次才会结束。

若在有限次内结束,则输出循环次数。否则输出死循环。

输入格式

多组数据,每组数据一行四个整数 A,B,C,k。

读入以 0 0 0 0 结束。

输出格式

若在有限次内结束,则输出循环次数。

否则输出 FOREVER。

数据范围

1≤k≤32,
0≤A,B,C< 2 k 2^k 2k

输入样例:
3 3 2 16
3 7 2 16
7 3 2 16
3 4 2 16
0 0 0 0
输出样例:
0
2
32766
FOREVER

思路

题意转化:
( a + n c ) % 2 k = = b (a+nc)\%2^k==b (a+nc)%2k==b➡️ a + n c − y ∗ 2 k = = b a+nc-y*2^k==b a+ncy2k==b➡️ n c − y ∗ 2 k = = b − a nc-y*2^k==b-a ncy2k==ba
现在又把问题转化为求线性同余方程

python代码

def exgcd(a,b):
    if b==0:
        return a,1,0
    else:
        d,x1,y1=exgcd(b,a%b)
        x=y1
        y=x1-a//b*y1
        return d,x,y

while True:
    a,b,c,k=map(int,input().split())
    if a==0 and b==0 and c==0 and k==0:
        break
    
    newk=-(1<<k)
    gcd,n,y=exgcd(c,newk)

    if (b-a)%gcd!=0:
        print('FOREVER')
    else:
        n*=(b-a)//gcd
        newk//=gcd
        print(n%newk)

知识点

  1. 扩展欧几里得算法,得到ax+by=gcd(a,b)的一组解,且所有的解的形式都能表示为:
    x = x 0 + k ∗ b g c d ( a , b ) , y = y 0 − k ∗ a g c d ( a , b ) x=x_0+k*\frac{b}{gcd(a,b)},y=y_0-k*\frac{a}{gcd(a,b)} x=x0+kgcd(a,b)b,y=y0kgcd(a,b)a
  2. 并且最小的非负解: x 0 % b g c d ( a , b ) x_0 \%\frac{b}{gcd(a,b)} x0%gcd(a,b)b , y 0 % a g c d ( a , b ) y_0\%\frac{a}{gcd(a,b)} y0%gcd(a,b)a

题目5 正则问题

考虑一种简单的正则表达式:

只由 x ( ) | 组成的正则表达式。

小明想求出这个正则表达式能接受的最长字符串的长度。

例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是: xxxxxx,长度是6。

输入格式

一个由x()|组成的正则表达式。

输出格式

输出所给正则表达式能接受的最长字符串的长度。

数据范围

输入长度不超过100,保证合法。

输入样例:
((xx|xxx)x|<(x|xx))xx 
输出样例:
6

思路

这一题应该是递归的范畴,直接dfs()即可

蓝桥杯笔记(超详细版):蓝桥杯备赛笔记

python代码

n=input().strip()
k=0#当前位置
def dfs():
    global k
    ans=0
    temp=0
    while k<len(n):
        if n[k]=='(':#进入新一层
            k+=1
            temp+=dfs()
        elif n[k]=='x':
            k+=1
            temp+=1
        elif n[k]=='|':#把(到|赋值给ans,temp归零
            k+=1
            ans=max(ans,temp)
            temp=0
        elif n[k]==')':
            k+=1
            ans=max(ans,temp)
            return ans#返回上一层
    ans=max(ans,temp)
    return ans
print(dfs())
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值