标签:时间 com time 产品 cti vector lin cpp stdout
又是一道\(DP\)的好题啊!状态并不明显,需要仔细分析,而且还结合了栈的特性!
做这一类题,只要出题人有点理想,一定会在栈的性质上做点文章,所以我们尽量围绕栈的性质设置\(DP\)状态。可是栈又有什么性质呢?讲真,考场我是真没想到,好像压根就不知道有这个特性:
对于队列里\([l,r]\)范围内的数,必然存在一个最晚出栈的\(i\in[l,r]\),而我们不难发现此时\([l,i-1]\)必然比\([i+1,r]\)出栈要早一些,因为\([i+1,r]\)进栈之前\(i\)就已经进栈了,而\(i\)又是最后一个出栈的(也就是说在\(i\)进栈时栈里一定是空的!!!不然:假设还有一个\(j\)未弹出,\(i\)进栈时会在\(j上面\),那么最晚出栈的就将会是\(j\)!!!)
所以不论\([l,i-1]\)的顺序是怎样的,他们对于后面的数所产生的(时间之和)与(惩罚值之和)是确定的!!!而此时如果我们知道\([l,i-1],[i+1,r]\)的总(时间之和)与(惩罚值之和)就能知道\([l,r]\)的总(时间之和)与(惩罚值之和)。所以我们应该先用这个方法先求\([l,i-1]\)与\([i+1,r]\)的最小(时间之和)与(惩罚值之和)再来得出\([l,r]\)。
转移方程:
\(f[l][r]=min(f[l][r],f[l][i-1]+f[i+1][r]+(st[i-1]-st[l-1])*(sd[r]-sd[i])+(st[r]-st[l-1])*d[i])\)
其中:
唉!现在一想明明如此浅显的道理我怎么在考场上就是想不到呢???果然还是太弱了,唉.........
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define db double
#define inf (ll)40000000001
#define rg register int
using namespace std;
int n;
int t[205];
int d[205];
ll st[205];
ll sd[205];
ll f[205][205];
inline int qr(){
char ch;
while((ch=getchar())<'0'||ch>'9');
int res=ch^48;
while((ch=getchar())>='0'&&ch<='9')
res=res*10+(ch^48);
return res;
}
int main(){
//freopen("product.in","r",stdin);
//freopen("product.out","w",stdout);
n=qr();
for(rg i=1;i<=n;++i){
t[i]=qr(),d[i]=qr();
st[i]=st[i-1]+t[i];
sd[i]=sd[i-1]+d[i];
}
for(rg i=1;i<=n;++i)
for(rg j=i;j<=n;++j)
f[i][j]=i==j?t[i]*d[i]:inf;
for(rg k=1;k<=n;++k)
for(rg l=1;l<=n-k;++l)
for(rg i=l,r=l+k;i<=r;++i)
f[l][r]=min(f[l][r],f[l][i-1]+f[i+1][r]+(st[i-1]-st[l-1])*(sd[r]-sd[i])+(st[r]-st[l-1])*d[i]);
printf("%lld\n",f[1][n]);
return 0;
}
产品排序(2015 年北大自招夏令营) (与栈相关的区间DP)
标签:时间 com time 产品 cti vector lin cpp stdout
原文地址:https://www.cnblogs.com/812-xiao-wen/p/10331497.html