k的倍数(同模相减-美团笔试编程题)

来源:互联网 发布:jdk 8u111 linux x64 编辑:程序博客网 时间:2024/04/28 12:04

问题描述:

序列中任意个连续的元素组成的子序列成为该序列的子串。现在给你一个序列p和一个整数k,询问元素和是k的倍数的子串的最大长度。比如序列[1,2,3,4,5],给定的k为5,其中满足条件的串子串为[5],[2,3],[1,2,3,4,5].所以答案是5

输入描述:

第一行一个整数n (1<=n<=10^5)

第二行n个整数的序列p(1<=pi<=10^5)

第三行含一个整数k(1<=k<=10^5)

输出描述:

输出一个ANS,表示答案

分析思路:

本人用的是python,刚开始想用暴力求解,但看数据o(n^2),必然WA,所以想用动态规划加二分求解,但还是挂了。后来想到了将动态规划降维的方法,即转化为利用sum[i]-sum[j]=t*k求i,j的最大距离。将p前缀加一个[0],便于统一下标。先遍历一遍p,从一个逐个相加,结果每个p[i]代表前p[:i+1]的和,每求一次,对t=p[i]%k。这里用一个r数组,存在余数对应位置存该余数出现的下标(这里有点拗口,即利用了r的下标即代表一个余数,这里就相当于降维了)。然后再定义一个数组ans,用于存储间隔值。下标即余数值,最终指出现p中的每项取余得到的相同余数的间隔最大值,存储在相应余数所对的下标中。现在回到r数组,至于r数组怎么跟ans何用呢?就是取余之后进行判断,如果r之前没存这个余数,说明这个余数第一次出现,存下下标(此处下标指的是遍历p的下标)。如果不是第一次出现,则计算距离第一次下标的值,并比较ans中相应余数对应的下标的ans值取大值。依次类推,然后最终求最大值。即答案。整个过程只需在遍历p求和的过程中即可完成,时间复杂度为o(n)。这里利用r和ans两个数组以及余数与下标相等的巧妙性将二维降成了一维。

ps:这里余数对应的下标,即余数值与下标值相等。

代码实现:

#-*-coding:utf-8 -*-while True:    try:        n=int(raw_input())        res=map(int,raw_input().split())        k=int(raw_input())        res=[0]+res        r=[-1 for i in range(n+1)]        ans=[-1 for i in range(n+1)]        r[0]=0        for i in range(1,n+1):            res[i]+=res[i-1]            t=res[i]%k            if r[t]!=-1:                m=i-r[t]                ans[t] = max(m, ans[t])            else:                r[t]=i        print max(0,max(ans))    except:        break


原创粉丝点击