BZOJ 1044: [HAOI2008]木棍分割 DP 前綴和優化
阿新 • • 發佈:2018-10-09
前綴 display namespace 木棍分割 狀態轉移方程 mat spl 指針 sca
題目鏈接
咳咳咳,第一次沒大看題解做DP
以前的我應該是這樣的
哇哢哢,這tm咋做,不管了,先看個題解,再寫代碼
終於看懂了,臥槽咋寫啊,算了還是抄吧
第一問類似於noip的那個跳房子,隨便做
這裏重點講第二問
首先,不會做,那就先寫暴力
dp當然得寫dp暴力了
\(f[k][i]\) 表示選擇了k段,到了第i個位置(一共有m+1段)
狀態轉移方程就是\[f[k][i]=f[k][i]+f[k-1][j](sum[i]-sum[j-1]<=ans)\]
for(int i=1;i<=n;++i) { if(sum[i]<=ans) f[1][i]=1; } for (int k=2;k<=m+1;++k) { for(int i=k;i<=n;++i) { for(int j=i;j>=1;--j) { if(sum[i]-sum[j-1] <= ans) { f[k][i] += f[k-1][j]; } } } }
三重循環,第一重枚舉k,第二重枚舉i,第三重枚舉j
好了,時間復雜度\(O(n^{2}*m)\),空間復雜度\(O(n*m)\),\(TLE\)(太不良心了,不給暴力分)
空間復雜度的話,很明顯可以滾動數組
考慮第三重循環,是上一次轉移的一段連續的區間
那麽,我們是不是可以把上一他們都前綴和,然後O(1)
那前綴和範圍不明確咋辦?
我們可以用數組O(n)預處理出來
**很明顯的 $i>j 則p[i]>=p[j] \(,指針從1一直往後挪,挪到n** ####**時間復雜度\)(n*m)\(,空間復雜度\)O(n)$,優秀~(≧▽≦)/~**
最後,註意邊界吧
/************************************************************** Problem: 1044 User: 3010651817 Language: C++ Result: Accepted Time:4528 ms Memory:11052 kb ****************************************************************/ #include <iostream> #include <cstdio> using namespace std; const int maxn = 5e5 + 7; const int mod = 10007; int a[maxn], n, m, l, r; int sum[maxn], p[maxn]; bool check(int x) { int js = 0, tot = 0; for (int i = 1; i <= n; ++i) { if (tot + a[i] > x) { js++, tot = 0; } tot += a[i]; } if (tot > x) return 0; return m >= js; } int f[2][maxn]; int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; ++i) scanf("%d", &a[i]), sum[i] = sum[i - 1] + a[i]; r = sum[n]; int ans = 0; while (l <= r) { int mid = (l + r) >> 1; if (check(mid)) ans = mid, r = mid - 1; else l = mid + 1; } p[1] = 1; for (int i = 2; i <= n; ++i) { p[i] = p[i - 1]; while (sum[i] - sum[p[i] - 1] > ans && p[i] <= i) { p[i]++; } } for (int i = 1; i <= n; ++i) p[i] = p[i] >= 2 ? p[i] - 2 : 0; for (int i = 1; i <= n; ++i) { if (sum[i] <= ans) { f[1][i] = 1; } f[1][i] = f[1][i - 1] + f[1][i]; } int tot = 0; for (int i = 2, cnt = 0; i <= m + 1; ++i, cnt ^= 1) { for (int j = i; j <= n; ++j) { f[cnt][j] = ((f[cnt][j - 1] + f[cnt ^ 1][j - 1]) % mod + mod - f[cnt ^ 1][p[j]]) % mod; } tot = ((tot + f[cnt][n]) % mod + mod - f[cnt][n - 1]) % mod; } printf("%d %d\n", ans, tot ); return 0; }
BZOJ 1044: [HAOI2008]木棍分割 DP 前綴和優化