問題:
小汪作為一個有數學天分的程序猿,設計了一套密碼生成器來搞定自己的密碼問題。
密碼生成器由N個槽位組成,槽位的下標為0~N-1,每個槽位存儲一個數。起初每個槽位都是0。
密碼生成器會進行M輪計算,每輪計算,小汪會輸入兩個數L,R(L<=R),密碼生成器會將這兩個數作為下標,將兩個下標之間(包含)的所有槽位賦值為i(i為當前的輪次,i∈[1,M])。
M輪計算完成后,密碼生成器會根據槽位的最終值生成一條密碼,密碼的生成規則為:
(0*a[0] + 1*a[1] + 2*a[2] + ... + (N-1)*a[N-1]) mod 100000009
其中a[i]表示第i個槽位的最終值。
請幫助小汪把他的密碼生成器實現為代碼。
鏈接:https://www.nowcoder.com/questionTerminal/96bf0c548a094de7a05919e0b32b1a5a?toCommentId=6455114
來源:牛客網
分析
(1)第一種方式,根據題意使用數組表示槽位。但是最壞的時間復雜度達到O(m*n),我的代碼只能通過30%的測試。 (2)第二種方式,使用問題轉換。只記錄分割片段,輸入數據的同時實時更新已經記錄的片段。最后通過數學公式獲得最終值。我的代碼在本地能通過題目提供的測試,但是在web端提交運行出現錯誤且未通過(您的代碼已保存
請檢查是否存在數組越界等非法訪問情況)。在這種方法中,槽位n並沒有被實際用到。
代碼
方式1代碼:

1 import java.util.Arrays; 2 import java.util.Scanner; 3 4 /** 5 *題目:小汪的密碼問題 6 * 使用數組記錄每個槽位 7 */ 8 public class Main6_1{ 9 public static void main(String args[]){ 10 Scanner in = new Scanner(System.in); 11 int n,m; 12 n = in.nextInt(); //槽位 13 m = in.nextInt(); //運算輪次 14 int[] dp = new int[n]; //創建槽位 15 int x,y; 16 //循環計算 17 for(int i=1;i<=m;i++){ 18 x = in.nextInt(); 19 y = in.nextInt(); 20 /*while(x<=y){ 21 dp[x++]=i; 22 dp[y--]=i; 23 }*/ 24 //內部實際也是遍歷填充 25 Arrays.fill(dp,x,y+1,i); 26 //System.out.println(Arrays.toString(dp)); //顯示每一輪計算后的結果 27 } 28 //根據規則計算結果值 29 double res = 0; 30 for(int i=0;i<n;i++){ 31 res+=i*dp[i]; 32 } 33 //對結果值取模 34 System.out.printf("%.0f",res%100000009); 35 } 36 }
方式2代碼:

1 import java.util.*; 2 3 /** 4 *題目:小汪的密碼問題 5 * 使用map記錄片段 6 * 動態分割片段:使用新片段分割老片段 7 * 8 * 存在四種情況 9 * 設已經存在的片段端點為a1,b1,新片段端點為a2,b2 10 * case1:a1<a2<=b1 11 * 分割結果:(a1,a2-1),(a2,b2) 12 * case2:a2<=a1 && b2>=b1 13 * 分割結果:(a2,b2) 14 * case3:a1<=b2<b1 15 * 分割結果:(b2+1,b1),(a2,b2) 16 * case4:a1<a2 && b2 > b1 17 * 分割結果:(a1,a2-1) (a2,b2),(b2+1,b1) 18 * 19 * 運行結果提示:請檢查是否存在數組越界等非法訪問情況 20 * 猜測:在外部對map進行了修改。測序出現錯誤 21 */ 22 public class Main6_2{ 23 public static void main(String args[]){ 24 Scanner in = new Scanner(System.in); 25 int m,n; 26 n = in.nextInt(); 27 m = in.nextInt(); 28 //記錄每次輪次的所有片段,因為前面的片段可能被后面的輪次進行更細小的切割 29 Map<Integer,Map<Integer,Integer>> dp = new HashMap<>(); 30 int a2,b2; 31 //循環輪次 32 for(int i=1;i<=m;i++){ 33 a2 = in.nextInt(); 34 b2 = in.nextInt(); 35 36 //更新已經存在的片段:覆蓋、再分割 37 for(int j=1;j<i;j++){ 38 //如果存在該輪dp.get(i)!=null && dp.get(i).size()>0次的片段,實施分割 39 if(dp.get(j)!=null && dp.get(j).size()>0){ 40 Map<Integer,Integer> curMap = dp.get(j); 41 for(Map.Entry<Integer,Integer> entry:curMap.entrySet()){ 42 int a1 = entry.getKey(); 43 int b1 = entry.getValue(); 44 if(a2>a1 && a2<=b1){ //case1:a1<a2<=b1 45 entry.setValue(a2-1); 46 }else if(a2<=a1 && b2>=b1){ //case2:a2<=a1 && b2>=b1 47 curMap.remove(a1); 48 }else if(b2>=a1 && b2<b1){ //case3:a1<=b2<b1 49 curMap.remove(a1); 50 curMap.put(b2+1,b1); 51 }else if(a1<a2 && b2>b1){ //case4:a1<a2 && b2 > b1 52 entry.setValue(a2-1); 53 curMap.put(b2+1,b1); 54 } 55 } 56 } 57 } 58 //放入當前片段 59 Map<Integer,Integer> tmp = new HashMap<>(); 60 tmp.put(a2,b2); 61 dp.put(i,tmp); 62 63 } 64 double res = 0; 65 /* 66 單個片段的計算公式: 67 (1)片段長度為count 68 (2)片段輪次為i 69 (3)片段首位坐標為為x,y 70 (4)計算公式整合:x*i+(x+1)*i .... +y*i = (x+(x+1)+...+y)*i 71 */ 72 for(int i=1;i<=m;i++){ 73 if(dp.get(i)!=null && dp.get(i).size()>0){ 74 Map<Integer,Integer> curMap = dp.get(i); 75 for(Map.Entry<Integer,Integer> entry:curMap.entrySet()){ 76 int x = entry.getKey(); 77 int y = entry.getValue(); 78 int count = y-x+1; 79 double v = (count*(x+y))/2.0; 80 res+=i*v; 81 } 82 } 83 } 84 System.out.printf("%.0f",res%100000009); 85 } 86 }