【NOIP2005】过河
生活随笔
收集整理的這篇文章主要介紹了
【NOIP2005】过河
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
本題在洛谷上的鏈接:https://www.luogu.org/problemnew/show/P1052
?
顯然可以拿到30分暴力分,直接開一個(gè)10^9的數(shù)組,然后跑最裸的DP就可以了。
但怎么優(yōu)化呢?這里有一種不錯(cuò)的方法——路徑壓縮。和并查集里那個(gè)并不完全一樣。
注意,我們只關(guān)注路徑上有沒有石頭,而不關(guān)注路徑是怎么走的,因此可以把兩塊石頭之間的距離壓縮。這里我們參考小凱的疑惑里推出的結(jié)論,假如每次走a或a+1步,那么大于等于a*(a+1)的步數(shù)均可以走出,這樣我們把大于t*(t-1)步的距離壓縮成t*(t-1)步即可,而t<=10,所以壓縮完后,肯定不會(huì)炸空間。壓縮完后再跑裸DP。
但注意這里我們用到了可以走t-1或t步,如果s=t就不滿足,需要討論,其實(shí)也很簡單,就是數(shù)數(shù)有多少塊石頭的位置是s或t的倍數(shù)即可。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int maxn = 1e4 + 15, inf = 0x3f3f3f3f; 8 9 int dp[maxn], stone[105], cnt[maxn]; 10 11 int main() { 12 int l, s, t, m, last = 0, ans = inf, ans2 = 0; 13 scanf("%d%d%d%d", &l, &s, &t, &m); 14 l = 0; 15 for (int i = 1; i <= m; ++i) scanf("%d", &stone[i]); 16 sort(stone + 1, stone + m + 1); 17 for (int i = 1; i <= m; ++i) { 18 int d = stone[i] - stone[i - 1]; 19 if (d > t * (t - 1)) d = t * (t - 1); 20 cnt[last += d] = 1; 21 l = max(l, last); 22 if (stone[i] % s == 0) ++ans2; 23 } 24 if (s == t) {printf("%d", ans2);return 0;} 25 memset(dp, inf, sizeof(dp)); 26 dp[0] = 0; 27 for (int i = 0; i < l; ++i) 28 for (int j = s; j <= t; ++j) { 29 dp[i + j] = min(dp[i + j], dp[i] + cnt[i + j]); 30 if (i + j >= l) ans = min(ans, dp[i + j]); 31 } 32 printf("%d", ans); 33 return 0; 34 } AC代碼?
轉(zhuǎn)載于:https://www.cnblogs.com/Mr94Kevin/p/9806746.html
總結(jié)
以上是生活随笔為你收集整理的【NOIP2005】过河的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何用JS获取页面上的所有标签
- 下一篇: 如何正确清洁家具,避免损坏?