1. 程式人生 > >k的倍數(同模相減-美團筆試程式設計題)

k的倍數(同模相減-美團筆試程式設計題)

問題描述:

序列中任意個連續的元素組成的子序列成為該序列的子串。現在給你一個序列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