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