首先我想吐槽的是题目并没有表明数据范围。。。
这个题目 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: 2059User: LYFerLanguage: C++Result: AcceptedTime:480 msMemory: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; }