kickstart 题目解析及代码 python

目录

2018

round C

kickstart alarm

round D

Candies

Paragliding

round E

yogurt

milk tea

round F

commonanagrams


 

2018

round C

kickstart alarm

题目链接

题目大意为根据一个数组A,A中共有N个数分别为A1,A2,。。。。,AN,利用其所有的连续子串来计算一组数P,P共有k个数,对于第k个数,起计算方法如下公式所示:

假设对于数组A,其所有可能的连续子串共有Ω个,令Ak,A(k+1),A(k+2),。。。,A(j)为其中第i个可行的子串,则其子串的指数和形式为如下的公式,结果记为Gi

                                                    G_{i}=A_{k}\cdot 1^{k}+A_{k+1}\cdot 2^{k}+....+A_{J}\cdot (j-k+1)^{k}

那么数Pk为所有Gi的和P_{k}=\sum G_{i}。相应的例子可以在题目链接中看到。

题目求解方法:

对于小数据集可以暴力求解,运行时间为O(N^3*K),求解代码如下:

def kickstartalarm():
    N, K, x1, y1, C, D, E1, E2, F = map(int, input('input N,K,x1,y1,C,D,E1,E2,F').split(' '))
    x = [x1]
    y = [y1]
    A = [x1 + y1]
    for i in range(1, N):
        x.append((C * x[i - 1] + D * y[i - 1] + E1) % F)
        y.append((D * x[i - 1] + C * y[i - 1] + E2) % F)
        A.append((x[i] + y[i])%F)
    constnumber=1000000007
    P=[0]*K
    res=0
    for k in range(K):
        for l in range(N):
            for r in range(l,N):
                for j in range(l,r+1):
                    P[k]+=A[j]*pow(j-l+1,k+1)
    result=sum(P)%1000000007
    return result,res

对于大数据集,由于存在时间限制,因此不可能用这样的方法,因此需要用巧一些的方法。因此我们对Pk的计算进行分析

有题目可知,Pk最终可以写为\sum_{j=0}^{N} \sum_{l}^{\Theta }A_{j}\cdot m^{k},其中Θ为多项式中Ai出现的总次数,现在分析Ai的乘积项m可能出现的数

对于包含Aj的数组,其长度范围为1(仅有Aj)到N(全部),在长度为N的数组里,m最大只能取到j,因此对任意子数组有1<=m<=j,接下来分析当m固定时总共会出现几次,即Θ的总数。在包含Aj的一个数组子串中,m表示Aj在该子串中的位置,分析下面两图:

m=1时

m=2时

 

即对于m可取的值,都会出现N-j+1次。那么Pk就可以写为P_{k}=\sum_{j=1}^{N}A_{j}\cdot m^{k}\cdot (N-j+1),接下来考虑Pk的总和,提取公因式Aj和N-j+1,可改写为下列形式

\sum P_{k}=A_{1}\cdot (N-j+1)*[(1+1^{2}+...+1^{k})+...(j+j^{2}+...+j^{j})]+...+A_{N}\cdot (N-j+1)*[](1+1^{2}+...+1^{k})+...(j+j^{2}+...+j^{j})]

因此可以利用等比数列求和公式来计算,由于k可能很大,因此在求幂的过程中,应该用快速幂的方法求解,同时注意到公式中中相邻的Ai,Ai+1,Ai+1括号内的数据比Ai的多了一项j+1,因此计算中不必每次都从1计算等比数列,可以记录下来减少计算。

对于等比数列求和,利用费马小定理可以将求模运算改写为下:

(b/a)%n=(b*a**(n-2))%n

同时,对于求幂过程中也利用求模公式减少计算。代码如下:耗时O(N*log(K))

def kickstartalarmBig():
    constmod = 1000000007

    def power(base, n):
        if n == 0:
            return 1
        else:
            result = power(base, n >> 1)
            if n & 1:
                return ((result * result) % constmod * base) % constmod
        return (result * result) % constmod

    N, K, x1, y1, C, D, E1, E2, F = map(int, input().split(' '))
    x = [x1]
    y = [y1]
    A = [(x1 + y1)%F]
    for i in range(1, N):
        x.append((C * x[i - 1] + D * y[i - 1] + E1) % F)
        y.append((D * x[i - 1] + C * y[i - 1] + E2) % F)
        A.append((x[i] + y[i]) % F)

    result = 0
    lastsum = 0
    for i in range(1, N + 1):
        if i == 1:
            lastsum += K
        else:
            # 费马小定理
            # (b/a)%n=(b*a**n-2)%n
            lastsum += i * (power(i, K) - 1) % constmod * power(i - 1, constmod - 2) % constmod
        lastsum
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值