CSP202104 4 校門外的樹

2022-09-19 03:45:09 字數 1519 閱讀 3353

原題點我

打眼一看,感覺是個dp,而我的dp很菜(其實不管什麼都很菜),看到區間就想到區間dp,導致有一點思路,但是無法實現。實際上我們不關心中間的某一段的種樹情況,只需要知道從第乙個障礙物開始到最後乙個障礙物結束的種樹方案,因此只需要一維陣列。

用\(f_i\)表示從第乙個障礙物到第\(i\)個障礙物的總方案數,那麼很容易寫出\(f_i = \sum_^\),其中\(calc(i, j)\)表示第\(i\)個障礙物到第\(j\)個障礙物之間的方案數。假設\(f_1\)到\(f_\)都已經求出來,那麼求\(f_i\)就只需要求出\(calc(i, j)\)。

現在我們設法寫出\(calc\)函式。顯然,對於中間沒有障礙物的兩個障礙物來說,他們之間的方案數就是兩個障礙物之間距離的約數(不包括自己)的個數。舉例: 設兩個障礙物的座標分別是\(a_i\)和\(a_\),那麼\(calc(i + 1, i) = sizeof(x)\),其中\(x\)表示\(a_ - a_i\)的約數(不包括自己)所組成的集合。那麼對於中間有障礙物的兩個障礙物來說呢?因為在dp的過程中,在列舉左端點\(j\)時,右端點\(i\)是不動的,所以我們就以右端點為基準。顯然,在集合x中的數都不能再作為現在的備選答案了,因為若選擇這些數作為答案,則從右端點開始計算,必將在之前的左端點處種下一棵樹,但實際上這是非法的操作。同樣地,之前的兩個障礙物之間的距離也不能作為備選答案。

具體來說,建立乙個初始為空的集合\(y\),從\(j = i - 1\)開始列舉倒序列舉\(j\),每次都找出\(a_i - a_j\)的約數所組成的集合\(z_j\),對於\(z_j\)中的每乙個元素,檢查它是否在集合\(y\)中,若在集合\(y\)中,則表明以這個元素作為間隔去種樹會在某乙個障礙物處種數,所以不能計入答案,若不在集合\(y\)中,則可以計入答案,並將其插入集合\(y\)中,處理完後,還要把\(a_i - a_j\)也加入集合中。

初始狀態: \(f_1 = 1\) 最終狀態: \(f_n = ?\)

#include #include #include #include #include #define ll long long

using namespace std;

const int maxn = 1e4 + 10;

const int maxm = 1e5 + 10;

const int m = 1e9 + 7;

int a[maxn];

vectorpr[maxm];

int n;

bool vis[maxm];

ll f[maxn];

ll calc(int p, int q);

int main()

printf("%lld\n", f[n] % m);

}ll calc(int p, int q)

vis[a[p] - a[q]] = true;

return ret % m;

}

倒序列舉\(j\)是比較關鍵的操作,想到這一步的原因是兩個相鄰的障礙物之間的方案數比較容易計算,而之後擴充套件到不相鄰的障礙物時,非法集合中的元素只增多不減少,比較容易維護。

校門外的樹

描述 某校大門外長度為 l的馬路上有一排樹,每兩棵相鄰的樹之間的間隔都是 1公尺。我們可以把馬路看成乙個數軸,馬路的一端在數軸 0的位置,另一端在 l的位置 數軸上的每個整數點,即0,1,2 l,都種有一棵樹。馬路上有一些區域要用來建地鐵,這些區域用它們在數軸上的起始點和終止點表示。已知任一區域的起...

校門外的樹

某校大門外長度為l的馬路上有一排樹,每兩棵相鄰的樹之間的間隔都是1公尺。我們可以把馬路看成乙個數軸,馬路的一端在數軸0的位置,另一端在l的位置 數軸上的每個整數點,即0,1,2,l,都種有一棵樹。由於馬路上有一些區域要用來建地鐵。這些區域用它們在數軸上的起始點和終止點表示。已知任一區域的起始點和終止...

校門外的樹

校門外的樹 題目描述 某校大門外長度為l的馬路上有一排樹,每兩棵相鄰的樹之間的間隔都是1公尺。我們可以把馬路看成乙個數軸,馬路的一端在數軸0的位置,另一端在l的位置 數軸上的每個整數點,即0,1,2,l,都種有一棵樹。由於馬路上有一些區域要用來建地鐵。這些區域用它們在數軸上的起始點和終止點表示。已知...