JAVA期末實驗:CSP 201809-4 原題

因爲防止作業重複,以及我抄我自己的情況出現,所以這裏暫時只提供思路,不附代碼。

賣菜(100分)

思路

這題沒啥難的,注意兩端計算方式是 ( a 1 + a 2 ) / 2 (a_1+a_2)/2 (a1+a2)/2 ( a n + a n − 1 ) / 2 (a_n+a_{n-1})/2 (an+an1)/2,而其他部分計算方式位 ( a i − 1 + a i + a i + 1 ) / 3 (a_{i-1}+a_i+a_{i+1})/3 (ai1+ai+ai+1)/3

買菜(100分)

思路

不能想當然地將兩人時間段一對一地比較,要考慮極端情況。假如一個人的某個時段的結束時間比另一個人的結束時間要短,那麼說明這個人的下一個時段也可能存在與另一個人同一段時間的交疊部分,因此繼續將這個人的下一個時間段與另一個人的同一段時間相比,如此重複,直到其中一人的時間段都比較完了。時間複雜度最好情況O(n),最壞情況O(n^2)。

元素選擇器(100分)

思路

對於單個的標籤或者id查詢是很容易實現的,難點在於如何處理後代選擇器。這裏有兩個思路,

第一種思路構造樹形結構,如圖所示,這樣很容易就能查到與當前點相關的子孫,按照深度遍歷次序搜索後代即可;
樹形結構

我採用的是第二種思路貪心策略,首構造一個文檔每行內容的一個數據結構,要包含三個屬性(級別、標籤和id),根據題目提示的貪心策略,對於當前行,其後級別不大於他的都是他的子孫。按照這個思路我設置了一個答案ans數組和緩衝buf數組,遍歷每一級查詢,buf中存的是當前級別上一級查詢的結果,逐個取出buf中的行號,從這個行號可是遍歷查詢他的子孫是否有當前要查詢的東西。

注意查詢和文檔的標籤要全部轉換爲小寫(大寫),此外,利用這種貪心的策略(樹形結構思路也一樣)會出現查詢 div p 時會將 div div p 認爲是兩個 div p,這樣就會出現重複,要注意去重

再賣菜(80分)

思路

用 a 表示第一天的價格,b 表示第二天的價格。

暴力方法:遍歷所有商鋪 a 的可能價格,進行驗證,必定會TLE。

該題看似狀態衆多,但是除了縮小邊界外,還可以根據數學關係以及已知的數來縮小狀態數,這樣就可以用dfs進行搜素了

我們首先分析題目,加上整除的計算方式,可以得到兩端的關係式

2 ∗ b 1 < = a 1 + a 2 < = 2 ∗ b 1 + 1 2*b_1<=a_1+a_2<=2*b_1+1 2b1<=a1+a2<=2b1+1

2 ∗ b n < = a n − 1 + a n < = 2 ∗ b n + 1 2*b_n<=a_{n-1}+a_n<=2*b_n+1 2bn<=an1+an<=2bn+1

其他部分的關係式爲

3 ∗ b i < = a i − 1 + a i + a i + 1 < = 3 ∗ b i + 2 3*b_i<=a_{i-1}+a_i+a_{i+1}<=3*b_i+2 3bi<=ai1+ai+ai+1<=3bi+2

對於兩端關係式(以起始端爲例),假如我們已經知道了 a 1 a_1 a1的值,那麼 a 2 a_2 a2的值就會被限制在有限的兩種可能中,即 2 ∗ b 1 − a 1 2*b_1-a_1 2b1a1 2 ∗ b 1 + 1 − a 1 2*b_1+1-a_1 2b1+1a1

同樣地,對於其他部分關係式,如果我們已經知道了 a i − 1 a_{i-1} ai1 a i a_i ai的值,那麼 a i + 1 a_{i+1} ai+1的值就會被限制在有限的三種可能中,即 3 ∗ b i − a i − 1 − a i 3*b_i-a_{i-1}-a_i 3biai1ai 3 ∗ b i + 1 − a i − 1 − a i 3*b_i+1-a_{i-1}-a_i 3bi+1ai1ai 3 ∗ b i + 2 − a i − 1 − a i 3*b_i+2-a_{i-1}-a_i 3bi+2ai1ai

這樣,我們可以遍歷 a 1 a_1 a1的所有可能,然後來搜索後續可能狀態,這樣可以保證之後每個點的狀態都不會超過三種,只需要搜索到倒數第二個點即可得到 a 的序列,然後用末尾端的關係式進行驗證

這樣的dfs搜索策略可以拿到80分,當 n 很大時,搜索狀態依然很多,還是會超時。

PS:這裏有一個優化策略,即剪枝。我們已經知道,後一個值是有前兩個值確定,那麼當遍歷到i點時,且訪問了某種 a i − 1 a_{i-1} ai1 a i a_i ai的值的組合,那麼不管其他值怎麼變化,再次在i點時,這種組合必然也不可能成功,所以沒必要對這種狀態搜索下去。

使用這種剪枝策略實現的C++代碼,能達到100分,但是,不知道爲什麼,Java剪枝後的時間效率反而不如不剪枝的,我猜測可能是因爲使用了較大的vis數組,使得Java的gc機制耗時更多了。

線性遞推式(20分)

思路

乍一看 l 可以很大,以爲是數組內存不夠的問題,再一看樣例,好傢伙還要考慮乘法溢出的問題,感覺巨難,沒啥思路,只能暴力20分,這個代碼不怕抄,可以附代碼。

代碼(20分)

import java.util.*;
public class q5 {
   
   
	private static Scanner sc;
	public static void main(String[] args) {
   
   
		sc=new Scanner(System.in);
		int m=sc.nextInt(),l=sc.nextInt(),r=sc.nextInt();
		sc.nextLine();
		long[] a=new long[r+1];
		long[] k=new long[100010];
		for(int i=1;i<=m;i++) {
   
   
			k[i]=sc.nextLong();;
		}
		a[0]=1;
		for(int i=1;i<=r;i++) {
   
   
			int min=(i<m ? i : m);
			for(int j=1;j<=min;j++) {
   
   
				a[i]=(a[i]+k[j]*a[i-j]%998244353)%998244353;
			}
		}
		for(int i=l;i<=r;i++) {
   
   
			System.out.println(a[i]);
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章