题意:给定m个多米诺骨牌,两两间距离为1,每个骨牌有一个高度h和花费p,推倒一个骨牌需要对应的代价p,可以选择向左或向右推,在选定方向上的h-1个(不包括自身)会被推倒,注意被推倒的骨牌会发生连锁反应,继续推。问:让所有的骨牌倒下,所需要的最小代价。
题解:输入是真的恶心,占据此题30%难度啊这
然后我们考虑如何DP
直接上单调栈
f[i]=min(f[left[i]-1]+co[i],mn[q[0]]);
left[i]表示i向左推能推到的最远点
q是单调栈,q[0]是长度
co是那个代价
q里面所有数满足h[q[pos]]]+q[pos]>i
其实就是向右推的
mn[q[0]]=min(f[i-1]+co[i],mn[q[0]-1]),就是i向右推
记得开long long,空间很大
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define ll long long
using namespace std;
ll i,j,k,m,n,o,p,l,s,t,times;
ll left[10000005],q[10000005],h[10000005],co[10000005],mn[10000005],f[10000005];
vector<ll> reh[300005],reco[300005];
void read(ll &x)
{
char ch=getchar();x=0;
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-48,ch=getchar();
}
int main()
{
freopen("shark.in","r",stdin);
freopen("shark.out","w",stdout);
read(n),read(m);
for (i=1;i<=n;i++)
{
read(o);
for (j=1;j<=o;j++) read(p),reh[i].push_back(p);
for (j=1;j<=o;j++) read(p),reco[i].push_back(p);
}
read(times);
for (i=1;i<=times;i++)
{
read(o),read(p);
for (j=0;j<=reh[o].size()-1;j++) h[++h[0]]=reh[o][j],co[++co[0]]=reco[o][j]*p;
}
for (i=m;i>=1;i--)
{
while (q[0]&&q[q[0]]-h[q[q[0]]]>=i) left[q[q[0]]]=i+1,q[0]--;
q[++q[0]]=i;
}
memset(q,0,sizeof(q));
for (i=m;i>=1;i--)
if (!left[i]) left[i]=1;
mn[0]=1e18;
for (i=1;i<=m;i++)
{
while (q[0]&&q[q[0]]+h[q[q[0]]]<=i) q[0]--;
f[i]=min(f[left[i]-1]+co[i],mn[q[0]]);
q[++q[0]]=i;
mn[q[0]]=min(f[i-1]+co[i],mn[q[0]-1]);
}
printf("%lld\n",f[m]);
return 0;
}
来源:oschina
链接:https://my.oschina.net/u/4375980/blog/4572205