蓝桥杯备赛(八)-数论
概念
通过引入质数筛、最大公约数、mod的性质、ex_gcd来作为蓝桥基础数论算法。
实例
Q1
等差数列(原题链接)
A1
本质寻求最大公差,需要注意为0的时候!!!特殊用例。
代码如下:
def gcd(a,b):
if b==0:
return a
c=a%b
if c!=0:
return gcd(b,c)
return b
n=int(input())
lst=list(map(int,input().split()))
lst.sort()
q_lst=[]
for i in range(1,n):
q_lst.append(lst[i]-lst[0])
d=gcd(q_lst[1],q_lst[0])
if d==0:
print(n)
else:
for i in range(2,n-1):
d=gcd(d,q_lst[i])
print((lst[-1]-lst[0])//d+1)
Q2
X的因子链(原题链接)
A1
需要用到质数筛,然后运用到一个数学基本定理:任何一个数可以由质数的乘积构成。于是这里就知道了该怎么引入因子链了吧。
代码如下:
def get_primes(n):
primes=[0 for _ in range(n+1)]
min_p=[0 for _ in range(n+1)]
st=[0 for _ in range(n+1)]
cnt=0
for i in range(2,n):
if not st[i]:
min_p[i]=i
primes[cnt]=i
cnt+=1
for j in range(cnt):
t=i*primes[j]
if t>n:
break
st[t]=1
min_p[t]=primes[j]
if i%primes[j]==0:
break
return primes,min_p,cnt
def fac(num):
res=1
for i in range(2,num+1):
res*=i
return res
if __name__=="__main__":
primes,min_p,_=get_primes(2000000)
while True:
try:
x=int(input())
pri=[0]*30
cnt2=[0]*30
k=0
while x>1:
pri[k]=min_p[x]
while x%pri[k]==0:
cnt2[k]+=1
x//=pri[k]
k+=1
tot=sum(cnt2)
times=fac(tot)
for i in range(k):
times//=fac(cnt2[i])
print(tot,times)
except:
break
Q3
聪明的燕姿(原题链接)
A3
难的想死,dfs+数论,自己看着办吧。dfs需要三个参数。
代码如下:
N=100000
st=[0 for _ in range(N+1)]
prime=[0 for _ in range(N+1)]
res=[]
cnt=0
def get_prime():
global cnt
for i in range(2,N+1):
if not st[i]:
prime[cnt]=i
cnt+=1
for j in range(cnt):
t=prime[j]*i
if t>N:
break
st[t]=1
if i%prime[j]==0:
break
def is_prime(n):
if n<=N:return not st[n]
for i in range(cnt):
if prime[i]*prime[i]>n:
break
if n%prime[i]==0:
return False
return True
def dfs(last,product,s):
if s==1:
res.append(product)
return
if last<0:
num=0
else:
num=prime[last]
#特判一次
if s-1>num and is_prime(s-1):
res.append(product*(s-1))
i=last+1
while prime[i]<=s/prime[i] and i <cnt:
p=prime[i]
j=1+p
t=p
while j<=s:
if s%j==0:
dfs(i,product*t,s//j)
t*=p
j+=t
i+=1
get_prime()
while True:
try:
n=int(input())
dfs(-1,1,n)
print(len(res))
if len(res):
print(' '.join(list(map(str,sorted(res)))))
res=[]
except:
break
Q4
五指山(原题链接)
A4
拓展欧几里得算法的运用。以及对于如何取最小正数的处理。
代码如下:
def exgcd(a,b):
global x,y
if b==0:
x,y=1,0
return a
else:
d=exgcd(b,a%b)
#这里是求下一层的,所以要递归上去的画,就得用减号
x_=y
y_=x-(a//b)*y
x=x_
y=y_
return d
#记住上面的算法,是有很大的学问的
for _ in range(int(input())):
n,d,a,b=map(int,input().split())
x,y=0,0
gcd=exgcd(n,d)
if not (b-a)%gcd:
y*=(b-a)//gcd
n//=gcd
print((y%n+n)%n)
else:
print('Impossible')
Q5
最大比例(原题链接)
A5
需要用到辗转相减。分子分母分离求。
代码如下:
#1223.最大比例
def gcd(a,b):
if b==0:
return a
c=a%b
if c==0:
return b
return gcd(b,c)
#辗转相减法
def sub_gcd(a,b):
if a>b:
t=a
a=b
b=t
if a==1:
return b
return sub_gcd(a,b//a)
n=int(input())
lst=list(set(sorted(list(map(int,input().split())))))
a=[]#存放分子
b=[]#存放分母
for i in range(1,len(lst)):
d=gcd(lst[i],lst[0])
a.append(lst[i]//d)
b.append(lst[0]//d)
up,down=a[0],b[0]
for i in range(1,len(a)):
up=sub_gcd(up,a[i])
down=sub_gcd(down,b[i])
print('{}/{}'.format(up,down))
Q6
糖果(原题链接)
A6
需要注意的是,这题利用状态压缩DP很快就能做出来。
代码如下:
n,m,k=map(int,input().split())
dp=[-1 for _ in range(1<<20)]#表示口味为v时所需要的最少糖果包数
st_lst=[]
tot=(1<<m)-1
for i in range(n):
st=0
lst=list(map(int,input().split()))
for j in range(k):
st|=(1<<lst[j]-1)#注意<<的优先级低于基础运算符号
dp[st]=1
st_lst.append(st)
for i in range(tot+1):
if dp[i]!=-1:
for j in range(n):
st=st_lst[j]
if dp[i|st]==-1 or dp[i|st]>dp[i]+1:
dp[i|st]=dp[i]+1
print(dp[tot])
Q7
C循环(原题链接)
A7
ex_gcd
代码如下:
def ex_gcd(a,b):
global x,y
if b==0:
x,y=1,0
return a
else:
d=ex_gcd(b,a%b)
x_=y
y_=x-(a//b)*y
x=x_
y=y_
return d
while True:
A,B,C,k=map(int,input().split())
if A==0 and B==0 and C==0 and k==0:
break
x,y=0,0
d=ex_gcd(C,1<<k)
if (B-A)%d==0:
x*=(B-A)//d
n=(1<<k)//d
print((x%n+n)%n)
else:
print('FOREVER')
Q8
正则问题(原题链接)
A8
主要在于如何构建递归搜索树,也就是我们的dfs。
代码如下:
def dfs():
global k
res=0
while k<len(str_):
if str_[k]=='(':
k+=1
res+=dfs()#进入下一层递归
k+=1#跳过)
elif str_[k]=='|':
k+=1
res=max(res,dfs())
elif str_[k]=='x':
res+=1
k+=1
elif str_[k]==')':
break
else:
break
return res
k=0
str_=input()
print(dfs())
总结
(xx.xx)