題意:ios
你在網上下載東西,一個文件存儲在一段或者多段裏面,問怎麼選擇能在規定的流量內下載最多的文件數量。每段的大小同樣。數組
思路:ide
習慣了作答案保存在DP數組裏的題,作這種答案保存在下標裏的題,轉不過彎來。開始想過揹包,可是一來內存不夠,二來時間也不夠。spa
實際上是這樣作的,dp[i][j][0/1]保存枚舉到第i個,下載了j個,最後一個是否被下載的最小花費。 最後找花費沒超過限制的最大值就行了。3d
最後值得注意的是,最後一段的時候,可能不會被p整除,不要算多了哦。code
代碼:blog
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #include <string> 8 #include <queue> 9 #include <stack> 10 #include <vector> 11 #include <map> 12 #include <set> 13 #include <functional> 14 #include <cctype> 15 #include <time.h> 16 17 using namespace std; 18 19 const int INF = 1<<30; 20 const int MAXN = 3055; 21 22 int dp[MAXN][MAXN][2]; //dp[i][j][k] 表示取到第i個,取了j個,的時候,第i個取或者不取 23 int a[MAXN]; 24 int sum[MAXN]; //前綴和 25 int n, p, l; 26 27 int main() { 28 #ifdef Phantom01 29 freopen("HNU12961.in", "r", stdin); 30 #endif //Phantom01 31 32 while (scanf("%d%d%d", &n, &p, &l)!=EOF) { 33 if (n==0&&p==0&&l==0) break; 34 35 sum[0] = 0; 36 for (int i = 1; i <= n; i++) scanf("%d", &a[i]); 37 for (int i = 1; i <= n; i++) sum[i] = sum[i-1]+a[i]; 38 for (int i = 0; i <= n; i++) 39 for (int j = 0; j <= n; j++) 40 dp[i][j][0] = dp[i][j][1] = INF; 41 dp[0][0][0] = 0; 42 43 for (int i = 1; i <= n; i++) { 44 for (int j= 0; j <= i; j++) 45 dp[i][j][0] = min(dp[i-1][j][0], dp[i-1][j][1]); 46 for (int j = 1; j <= i; j++) 47 dp[i][j][1] = min(dp[i-1][j-1][0]-(sum[i-1]/p)*p, 48 dp[i-1][j-1][1]-((sum[i-1]+p-1)/p)*p) 49 + (i==n ? sum[i] : ((sum[i]+p-1)/p)*p); 50 } 51 int ans = 0; 52 for (int i = 0; i <= n; i++) 53 if (dp[n][i][0]<=l || dp[n][i][1]<=l) 54 ans = max(ans, i); 55 printf("%d\n", ans); 56 } 57 58 return 0; 59 }