zoukankan      html  css  js  c++  java
  • CF802C Heidi and Library (hard)

    题目描述

    你有一个容量为k的空书架,现在共有n个请求,每个请求给定一本书ai,如果你的书架里没有这本书,你就必须以ci的价格购买这本书放入书架。当然,你可以在任何时候丢掉书架里的某本书。请求出完成这n个请求所需要的最少价钱。

    题解

    对于每个请求,我们可以强制让他必须买,然后再去考虑如何扣掉之前的贡献。

    对于每一次购买,我们可以作如下两种策划。

    1、刚买完就扔掉。2、在下一次购买之前把这本书卖掉(这里的卖掉相当于是把上一次买的代价减去了)。

    按照这样的策略,我们的每一本买来的书最终都会被弄掉 。

    这样的话,我们给每一次购买开一个垃圾桶,表示这本书经过若干轮之后必须回到垃圾桶里。

    设源点为S,汇点为T。

    从源点向每次询问连边权为1,费用为w的边,表示每次询问一定要买。

    每次询问向每次的垃圾桶连边权为1,费用为0,表示我可以刚买完就扔掉。

    每次询问向下一个询问连边权为k-1,费用为0的边,表示在下一次购买前我最多可以有k-1本书。

    对于一次询问,如果下一次询问的书之前出现过,则一条从当前询问到那一次的垃圾桶连一条边权为1,费用-w的边,代表把书卖掉的情况。

    费用流即可。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define N 170
    #define inf 1e9
    using namespace std;
    queue<int>q;
    int head[N],tot=1,ans,fl[N],dis[N],pre[N],n,k,a[N],c[N],now[N];
    bool vis[N];
    inline int rd(){
        int x=0;char c=getchar();bool f=0;
        while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return f?-x:x; 
    }
    struct edge{
        int n,to,l,f;
    }e[N*N];
    inline void add(int u,int v,int l,int f){
        e[++tot].n=head[u];e[tot].to=v;head[u]=tot;e[tot].l=l;e[tot].f=f;
        e[++tot].n=head[v];e[tot].to=u;head[v]=tot;e[tot].l=0;e[tot].f=-f;
    }
    inline bool spfa(int s,int t){
        memset(dis,0x3f,sizeof(dis));
        q.push(s);dis[s]=0;fl[s]=inf;
        while(!q.empty()){
            int u=q.front();q.pop();vis[u]=0;
            for(int i=head[u];i;i=e[i].n){
                int v=e[i].to;
                if(dis[v]>dis[u]+e[i].f&&e[i].l){
                    dis[v]=dis[u]+e[i].f;//cout<<u<<" "<<v<<" "<<dis[u]<<" "<<dis[v]<<endl;
                    pre[v]=i;fl[v]=min(fl[u],e[i].l);
                    if(!vis[v]){vis[v]=1;q.push(v);}
                }
            }
        }
        return dis[t]!=0x3f3f3f3f;
    }
    void calc(int s,int t){
        int x=t;
        while(x!=s){
            int i=pre[x];
            e[i].l-=fl[t];e[i^1].l+=fl[t];
            x=e[i^1].to; 
        }
        ans+=fl[t]*dis[t];
    }
    int main(){
        n=rd();k=rd();
        for(int i=1;i<=n;++i)a[i]=rd();
        for(int i=1;i<=n;++i)c[i]=rd();
        for(int i=1;i<=n;++i){
            if(i!=n)add(i,i+1,k-1,0);
            add(0,i,1,c[a[i]]);
            add(i,i+n,1,0);add(i+n,2*n+1,1,0);now[a[i]]=i;
            if(now[a[i+1]]){
                add(i,now[a[i+1]]+n,1,-c[a[i+1]]);
            }
        }
        while(spfa(0,2*n+1))calc(0,2*n+1);
        cout<<ans; 
        return 0;
    }
    View Code
  • 相关阅读:
    cross apply / outer apply
    查看锁表
    常用的一些占位符
    如何将法向量转换到世界空间
    Essential Mathematics for Games and Interactive Applications
    下一本要看的书
    第五章第五节 四元数
    向量坐标转换、旋转矩阵以及视图转换
    怪诞行为学摘录
    unity3d发布apk资源打包和访问方式
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/10502766.html
Copyright © 2011-2022 走看看