CF802C-Heidi and Library(hard)【费用流】

1|0正题

题目链接:https://www.luogu.com.cn/problem/CF802C


1|1题目大意

你有一个可以放 k 本书的书架,第 i 天要求书架上有第 ai 种书,购买第 i 种书的价格为 ci

求满足 n 天要求的最小花费。

1n,k80,1ci106


1|2解题思路

我们注意到每一天的限制是不能超过 k 本书延续到下一天。而书的保留我们可以考虑视为将一本书从这一天延续到下一次需要这本书的时候免费拿一本新的。

好那么现在相当于我们可以通过霸占一些区间来减少花费,但是一个格子最多被区间包含 k 次。

这和[NOI2008] 志愿者招募很像,考虑使用费用流来做本题。

首先我们要固定总流量为 n ,然后考虑怎么建图。这里将一个点拆为三部分记为 p(x,1/2/3)

  1. 获取点,用来流过今天需要的书。
  2. 储存点,表示流过的这本书已经使用完了。
  3. 商店点,流过多余的流量,购买书时从这个点流过。

然后要实现以下功能

  • 要求满足每天的条件:我们让 p(x,1)p(x,2) ,流量为 1 ,费用为 ,表示每天的条件必须满足。
  • 延续这本书到下一个同样需求的点yp(x,2)p(y,1),流量为 1 ,费用为 0 ,表示这本书用完之后可以留给后面的用。
  • 购买一本书: p(x,3)p(x,1) ,流量为 1 ,费用为 cax
  • 丢弃一本书: p(x,2)p(x+1,3) ,流量为 1 ,费用为 0 。因为这本书今天已经借出了所以需要占用空间,明天才能丢掉。
  • 限制存有书的数量不超过 k :考虑到我们相当于总共有 n 点流量,在 1/2 类点之间的流量都相当于目前存在书柜里的,所以商店的书至少需要为 nk 本。那么我们让 p(x,3)p(x+1,3) 流量为 nk ,费用为 ,这样这些流量就必须流过了,然后再建立一条 p(x,3)p(x+1,3) 流量为 ,费用为 0 的给多余的流过就好了。

费用为 的我们设为一个很大的值,最后将答案把这些值加回去就好了。

就可以通过本题了


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define ll long long using namespace std; const ll N=1e4+10,inf=1e9; struct node{ ll to,next,w,c; }a[N<<1]; ll n,k,tot,ans,op[N],c[N],las[N]; ll s,t,ls[N],f[N],pre[N],mf[N]; bool v[N];queue<ll> q; void addl(ll x,ll y,ll w,ll c){ a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;a[tot].c=c; a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;a[tot].c=-c; return; } bool SPFA(){ memset(f,0x3f,sizeof(f));pre[t]=0; f[s]=0;q.push(s);v[s]=1;mf[s]=inf; while(!q.empty()){ ll x=q.front();q.pop();v[x]=0; for(ll i=ls[x];i;i=a[i].next){ ll y=a[i].to; if(a[i].w&&f[x]+a[i].c<f[y]){ f[y]=f[x]+a[i].c;pre[y]=i; mf[y]=min(mf[x],a[i].w); if(!v[y])v[y]=1,q.push(y); } } } return pre[t]; } ll update(){ ll x=t; while(x!=s){ a[pre[x]].w-=mf[t]; a[pre[x]^1].w+=mf[t]; x=a[pre[x]^1].to; } return mf[t]*f[t]; } signed main() { scanf("%lld%lld",&n,&k);tot=1; for(ll i=1;i<=n;i++)scanf("%lld",&op[i]); for(ll i=1;i<=n;i++)scanf("%lld",&c[i]); ll w=0;s=3*n+2;t=s+1; addl(s,2*n+1,n,0); for(ll i=1;i<=n;i++){ if(las[op[i]]) addl(las[op[i]]+n,i,1,0); else w=min(w+1,k); addl(i+2*n,i,1,c[op[i]]); addl(i,i+n,1,-inf);ans+=inf; addl(i+n,i+2*n+1,1,0); las[op[i]]=i; if(n>w){ addl(i+2*n,i+2*n+1,n-w,-inf); ans+=(n-w)*inf; } addl(i+2*n,i+2*n+1,inf,0); } addl(3*n+1,t,n,0); int k=0; while(SPFA())ans+=update(); printf("%lld\n",ans); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/15879351.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-02-10 AT3949-[AGC022D]Shopping【贪心】
点击右上角即可分享
微信分享提示