首先我想吐槽的是题目并没有表明数据范围。。。
这个题目 DP方程并不难表示。
dp[i][j]表示前i个地点携带了j个货物的最小花费
dp[i][j] = dp[i-1][k] + (j-k) * cost + j*j*(leng[i]-leng[i-1])
如果你这样直接提交上去,恭喜你超时!!! 因为这个时间复杂度是 O(n*k^2)
所以我们需要优化一下,可以发现式子可以化简为:
dp[i][j] = dp[i-1][k] - k * cost + j*j*(leng[i]-leng[i-1]) + j*cost
dp[i][j] = dp[i-1][k] - k * cost 这一部分可以只是与k有关,这里我们可以用单调队列进行优化,使其保持 最小值。
坑点1:注意数据范围
坑点2:注意初始化
/************************************************************** Problem: 2059 User: LYFer Language: C++ Result: Accepted Time:480 ms Memory:61600 kb ****************************************************************/ #include <stdio.h> #include <string.h> #include <algorithm> #include <queue> #define mp(a,b) make_pair(a,b) #define fr(a,b,c) for(int c=a;c<=b;++c) using namespace std; typedef long long ll; const ll INF = 1e16; ll dp[777][10005]; int n,e,k; inline int Read(){ int ans = 0, flag = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch=='-') flag=-1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ ans = ans * 10 + ch - '0'; ch = getchar(); } return ans * flag; } struct task{ ll now,num,cost; bool operator <(const task &x) const{ return now < x.now; } }feed[505]; struct DanDiao{ deque< pair<ll,int> >Q; void insert(ll x,int y){ while( !Q.empty() && Q.back().first >= x) Q.pop_back(); Q.push_back( mp(x,y) ); } void erase(int y){ while( !Q.empty() && Q.front().second <= y) Q.pop_front(); } }DD; int main(){ k = Read(); e = Read(); n = Read(); fr(1,n,i){ feed[i].now = Read(); feed[i].num = Read(); feed[i].cost = Read(); } sort(feed+1,feed+1+n); feed[++n] = (task){e,0,0}; for(int i=0;i<=n;i++){ for(int j=0;j<=k;j++){ dp[i][j] = INF; } } dp[1][0] = 0; fr(2,n,i){ DD.Q.clear(); int r = 0; fr(0,k,j){ while(r <= j) DD.insert(dp[i-1][r] - r*feed[i-1].cost , r) , r++; DD.erase(j - feed[i-1].num - 1); if( DD.Q.empty()) dp[i][j] = INF; else dp[i][j] = DD.Q.front().first+j*feed[i-1].cost+j*j*(feed[i].now-feed[i-1].now); } } /*for(int i=1;i<=n;i++){ for(int j=0;j<=k;j++){ printf("dp[%d][%d]:%d\n",i,j,dp[i][j]); } }*/ printf("%lld\n",dp[n][k]); return 0; }