CF797F(Mice and Holes 单调队列优化dp)

题目
在这里插入图片描述
肯定要所有老鼠的位置 和 所有洞的位置都排序。 这不是显然的嘛
dp[i][j]:前j个老鼠进入第i个洞的最少花费。注意j要从0-n开始扫描!!!并不是1-n。
dp[i][j]=min(dp[i][k]+sum[i][j]-sum[i][k]). (j-k<=cav[i].c&&k<=j) k也可以等于j,此时就是第i个洞没老鼠。这样就不需要对于每一个i就ans=min(ans,dp[flag^1][n])了。直接答案就是i:1-m个洞扫完处理之后 dp[flag^1][n];
sum[i][j]:前j个老鼠都进入第i个房间的花费。 sum[i][j]-sum[i][k]:第[k+1,j]个老鼠进入房间i的花费。
然后随着j的增大,k的下界k>=j-cav[i].c 上界j也在单调递增,就是单调队列优化dp,可以滚动数组优化。
再者需要注意的就是初始化!!! dp[0][j:1-n]=INF,这一点很好理解,但是dp[0][0]是0啊呜呜呜。 还有INF要开大。。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=5e3+5,M=5e5+4;
const ll INF=1e13+5;
struct Hole{int pos,c;}cav[M];
inline int cmp(Hole A,Hole B){return A.pos<B.pos;}
int mouse_pos[N];
int q[N],flag=0;ll dp[2][N],sum[N];
//dp[i][j]=min(dp[i-1][k]+sum[i][j]-sum[i][k]) (j-k<=b[i].c&&k<=j-1)
//dp[i][j]=sum[i][j]+min(dp[i-1][k]-sum[i][k]) (j-b[i].c<=k<=j-1)
inline ll get_val(int k){
    return dp[flag][k]-sum[k];
}
inline void get_dp(int j,int k){
    dp[flag^1][j]=dp[flag][k]+sum[j]-sum[k];
}
int main(){
    int n,m,SUM=0;scanf("%d%d",&n,&m);
    for(int j=1;j<=n;++j) scanf("%d",&mouse_pos[j]);
    for(int i=1;i<=m;++i) scanf("%d%d",&cav[i].pos,&cav[i].c),SUM+=cav[i].c;
    if(SUM<n) {printf("-1");return 0;}
    sort(mouse_pos+1,mouse_pos+n+1);
    sort(cav+1,cav+m+1,cmp);
    for(int j=1;j<=n;++j) dp[flag^1][j]=INF;//千万要注意dp[flag^1][0]=0,不是INF 呜呜呜
    for(int i=1;i<=m;++i){
        int head=1,tail=0;flag^=1;
        for(int j=0;j<=n;++j){
            if(j) sum[j]=sum[j-1]+abs(mouse_pos[j]-cav[i].pos);
            while(head<=tail&&j-q[head]>cav[i].c) ++head;
            while(head<=tail&&get_val(q[tail])>=get_val(j)) --tail;
            q[++tail]=j,get_dp(j,q[head]);
        }
    }
    printf("%lld\n",dp[flag^1][n]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值