题意:一台机器要按照顺序完成n个任务,每个任务都有一个代价f和需要时间t。机器完成任务的方式是分批处理,对于每一批任务需要首先预处理s时间,同批任务中所有单个任务都是同时完成,代价为完成的时刻乘以各自的代价。求最小代价
思路:
分批考虑情况太多,可以先将问题转化。每个任务对对最后代价的贡献实际上等于它及它以后的f之和乘以它的时间t,即后面的任务都要为它等上t的时间,会多花f*t的代价。
找i的决策点的方法即min(dp[p]+(st[i]-st[p]+s)*sf[i]),st[i]为>=i的时间总和,sf[i]为大于等于i的代价总和,若两个决策点,j,k(j<k),存在j不比k更差,则意味着:
dp[j]+(st[i]-st[j]+s)*sf[i]<=dp[k]+(st[i]-st[k]+s)*sf[i] ==> (dp[j]-dp[k])/(st[j]-st[k])<=sf[i]
我们记用g(j,k)为用决策点j去取代k的代价函数,即考虑第i个点的时候如果发生了g(j,k)<=sf[i],那么用k就不如用j。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[12000],st[12000],sf[12000],L[12000]; int main() { int n,s; while(scanf("%d%d",&n,&s)!=EOF) { for(int i=1;i<=n;i++) scanf("%d%d",st+i,sf+i); dp[n+1]=st[n+1]=sf[n+1]=0; for(int i=n;i>=1;i--) st[i]+=st[i+1],sf[i]+=sf[i+1]; int a=0,b=0; L[a]=n+1; for(int i=n;i>=1;i--) { while(a<b&&dp[L[a+1]]-dp[L[a]]<=(st[L[a+1]]-st[L[a]])*sf[i]) a++; dp[i]=dp[L[a]]+(st[i]-st[L[a]]+s)*sf[i]; while(a<b&&(dp[i]-dp[L[b]])*(st[L[b]]-st[L[b-1]])<=(st[i]-st[L[b]])*(dp[L[b]]-dp[L[b-1]])) b--; L[++b]=i; } printf("%d\n",dp[1]); } return 0; }