蓝桥杯第八届省赛JAVA真题----k倍区间
標題: k倍區間
給定一個長度為N的數列,A1, A2, ... AN,如果其中一段連續的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍數,我們就稱這個區間[i, j]是K倍區間。??
你能求出數列中總共有多少個K倍區間嗎???
輸入
-----
第一行包含兩個整數N和K。(1 <= N, K <= 100000)??
以下N行每行包含一個整數Ai。(1 <= Ai <= 100000)??
輸出
-----
輸出一個整數,代表K倍區間的數目。??
例如,
輸入:
5 2
1??
2??
3??
4??
5??
程序應該輸出:
6
資源約定:
峰值內存消耗(含虛擬機) < 256M
CPU消耗? < 2000ms
請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。
所有代碼放在同一個源文件中,調試通過后,拷貝提交該源碼。
不要使用package語句。不要使用jdk1.7及以上版本的特性。
主類的名字必須是:Main,否則按無效代碼處理。
思路:題目中的例子6種情況為:2 4 123 345 1234 2345 。這不是一道難度很大的題,至少在理解上是的,但是一般思路做出來的方法肯定是得不了滿分的,這可能也是藍橋杯的另一種“套路”吧,將題目的理解變簡單,但是要求變困難。這里就更能體現出算法的重要性。
一開始上來就這直接暴力求了,結果做完時間復雜度為O(n^3),嚴重超時,甚至還有一個非常不必要的嵌套。
import java.util.Scanner; public class Main {static int n = 0;static int k = 0;static int[] a;static int cnt = 0;public static void main(String[] args) {Scanner in = new Scanner(System.in);n = in.nextInt();k = in.nextInt();a = new int[n+1];for (int i = 0; i < n; i++) {a[i] = in.nextInt();}for (int i = 0; i < n; i++) {for (int j = i; j < n; j++) {if (sum(i, j)% k == 0) {cnt++;}}}System.out.println(cnt);}private static int sum(int i, int j) {// TODO Auto-generated method stubint s = 0;for (int k = i; k <= j; k++) {s += a[k];}return s;} }接下來,消除嵌套之后,時間復雜度降到了O(n^2),但實際上這個題目必須達到線性O(n)才能得到滿分。
import java.util.Scanner; public class Main {static int n = 0;static int k = 0;static int[] a;static int cnt = 0;static int sum;public static void main(String[] args) {Scanner in = new Scanner(System.in);n = in.nextInt();k = in.nextInt();a = new int[n+1];for (int i = 0; i < n; i++) {a[i] = in.nextInt();}for (int i = 0; i < n; i++) {sum = 0;for (int j = i; j < n; j++) {sum += a[k];if (sum % k == 0) {cnt++;}}}System.out.println(cnt);} }參考了大神的代碼2017第八屆藍橋杯C/C++ B組省賽題解
下面這個代碼非常巧妙,將前綴和保存到數組中,減少每次不必要的嵌套計算,而同時%k會產生兩種結果,0或者小于k,這相當于直接記錄了符合(%k = 0)與不符合(%k < k)兩種情況。根據(sum[r] - sum[l-1]) % k == 0 就可以判斷一個區間[l, r]是符合約束區間。但是這樣會使用雙重循環,時間復雜度為O(n^2),這樣并沒有完全把這種算法的好處利用到,而且我們的目的是計算個數,而非要輸出所有的k倍區間。
根據上面的式子我們可以看出只要區間兩端點的前綴和%k相等,那么這段區間就符合約束,所以我們只需每次使sum加上與當前位置前綴和%k相等的數量(即bk[a[i]]++)就行。
(注意最后的結果還要加上前綴和%k=0的值,這是它自身到1的區間,也符合約束。)
import java.util.Scanner; public class Main {static int n = 0;static int k = 0;static int sum;static int[] a;static int[] bk;static int cnt = 0;public static void main(String[] args) {Scanner in = new Scanner(System.in);n = in.nextInt();k = in.nextInt();a = new int[n+1];bk = new int[n+1];for (int i = 0; i < n; i++) {a[i] = in.nextInt();}a[0] %= k;for (int i = 1; i < n; i++) {a[i] = (a[i] + a[i-1]) % k;}for (int i = 0; i < n; i++) {sum += (bk[a[i]]++);}System.out.println(sum + " "+ bk[0]);} }?
?
?
總結
以上是生活随笔為你收集整理的蓝桥杯第八届省赛JAVA真题----k倍区间的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 脚本的力量:MSDN中一段代码的Iron
- 下一篇: 迭代子模式(Iterator)