title

BZOJ 4946

LUOGU 3826

简化题意:

定义了一种蔬菜为:\(ai,si,ci,xi\),意思是蔬菜的价格为 \(a_i\),第一份卖出时价格为 \(a_i+s_i\),一共有 \(c_i\) 份,每天会有 \(x_i\) 份过期;每天最多卖出 \(m\) 份蔬菜,多组输入天数依次最大化收入。

analysis

首先,这道题目有一个费用流的写法(和今年 \(NOI2019D1T3\) 一样)。

因为保质期不好限制,我们把每种蔬菜都按照过期时间分成若干类,每类大概 \(x\) 个,这样就相当于我们有了 \(n\times p\) 种蔬菜;每种蔬菜在指定时间过期;我们把 \(s\) 的奖励放到每一种蔬菜过期时间最晚的那一类中去。

所以建图如下:

  1. \(源点s\) 向 \(每一天i\) 连边,容量为 \(m\),费用为 0;
  2. \(每一天i\) 向 \(所有在第i天过期的蔬菜\) 连边,容量为为 \(inf\),费用为 \(a\);
  3. \(每一天i\) 向 \(下一天i+1\) 连边,容量为 \(inf\),费用为 0;
  4. \(每种蔬菜\) 向 \(汇点t\) 连边,容量为 \(个数\),费用为 0;
  5. 针对每一种蔬菜的最后一类,我们分出来 1 个流量建出费用为 \(s\) 的边。

这样点数是 \(O(np+p)\),边数是\(O(np+n+p)\)的。

一天一天的增广费用流,可以跑过前 \(60pts\) (不知道为什么我的费用流写的有些丑,只跑过了 \(52pts\) ) 。

然后性质\(1,2\) 直接贪心可以再搞 \(16pts\) 。

然后就可以考虑正解了。

我们发现对于 \(p=i\) 时,我们所选择的蔬菜,一定是 \(p=i+1\) 时所选择的蔬菜的子集。这样我们跑费用流的时候,每次增加一个新点的时候是不会退流的。所以是可以贪心模拟费用流的增广过程,并且用数据结构维护一下就好了。

所以想法就多了,可以用堆,线段树,并查集,\(etc.\)

我写了堆和并查集(这个代码长度极其好评)的,堆的写法,我觉得看看 yyb 大爷的 \(blog\) 最好了。

并查集的写法很神奇,这种写法是在考虑卖的菜,贵菜先卖,但同时菜也要尽量在变质的时候再卖,然后用并查集维护最近的还能卖的天数,把菜尽量往后塞,如果位置没了,就说明这颗菜不需要了。

code

费用流\(60pts~+\)性质\(1\&\&\)性质\(2~16pts\)

#include<bits/stdc++.h>
#define mp make_pair
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=1e5+10,maxm=1e6+10,inf=0x3f3f3f3f;char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{x=0;T f=1, ch=getchar();while (!isdigit(ch) && ch^'-') ch=getchar();if (ch=='-') f=-1, ch=getchar();while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();x*=f;
}char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x)
{if (!x) *fe++=48;if (x<0) *fe++='-', x=-x;T num=0, ch[20];while (x) ch[++num]=x%10+48, x/=10;while (num) *fe++=ch[num--];*fe++='\n';
}struct QwQ{int a,s,c,x;}f[maxn];
struct Orz{int id,x;}q[maxn];
inline bool operator < (Orz a,Orz b)
{return a.x<b.x;
}int n,m,k;
ll ans[maxn];
namespace solve1
{inline bool cmp(QwQ a,QwQ b){return a.a>b.a;}inline void G(){sort(f+1,f+n+1,cmp);int now=1; ll res=0;for (int i=1; i<=k; ++i){int tmp=(q[i].x-q[i-1].x)*m;while (tmp && now<=n){if (f[now].c>=tmp){f[now].c-=tmp; res+=(ll)tmp*f[now].a;if (!f[now].c) ++now;break;}tmp-=f[now].c; res+=(ll)f[now].c*f[now].a;++now;}ans[q[i].id]=res;}for (int i=1; i<=k; ++i) write(ans[i]);flush();}
}namespace solve2
{pii num[maxn<<1];inline bool cmp(pii a,pii b){return a.first>b.first;}inline void G(){int tot=0;for (int i=1; i<=n; ++i){num[++tot]=mp(f[i].a+f[i].s,1);if (f[i].c-1) num[++tot]=mp(f[i].a,f[i].c-1);}sort(num+1,num+tot+1,cmp);int now=1; ll res=0;for (int i=1; i<=k; ++i){int tmp=(q[i].x-q[i-1].x)*m;while (tmp && now<=tot){if (num[now].second>=tmp){num[now].second-=tmp; res+=(ll)tmp*num[now].first;if (!num[now].second) ++now;break;}tmp-=num[now].second; res+=(ll)num[now].second*num[now].first;++now;}ans[q[i].id]=res;}for (int i=1; i<=k; ++i) write(ans[i]);flush();}
}namespace solve3
{int ver[maxm*7],edge[maxm*7],Next[maxm*7],cost[maxm*7],head[maxm],len=1;inline void add(int x,int y,int z,int c){ver[++len]=y,edge[len]=z,cost[len]=c,Next[len]=head[x],head[x]=len;ver[++len]=x,edge[len]=0,cost[len]=-c,Next[len]=head[y],head[y]=len;}int s,t,tot=0,pre[maxm];ll dist[maxm];bool vis[maxm];inline bool spfa(){memset(dist,-inf,sizeof(dist));memset(pre,0,sizeof(pre));deque<int>q;q.push_back(s);dist[s]=0;while (!q.empty()){int x=q.front();q.pop_front();vis[x]=0;for (int i=head[x]; i; i=Next[i]){if (!edge[i]) continue;int y=ver[i];if (dist[y]<dist[x]+cost[i]){dist[y]=dist[x]+cost[i]; pre[y]=i;if (!vis[y]){if (!q.empty() && dist[q.front()]<dist[y]) q.push_front(y);else q.push_back(y);vis[y]=1;}}}}return pre[t];}int id[1010][1010];inline void G(){s=0,t=++tot;for (int i=1; i<=n; ++i){for (int j=1; j<q[k].x; ++j){id[i][j]=++tot;if (j!=1) add(id[i][j-1],id[i][j],inf,0);if (f[i].c<=f[i].x) { add(tot,t,f[i].c-1,0),f[i].c=0; break; }f[i].c-=f[i].x;add(id[i][j],t,f[i].x,0);}if (f[i].c){int j=q[k].x;id[i][j]=++tot;if (j!=1) add(id[i][j-1],id[i][j],inf,0);add(tot,t,f[i].c-1,0),f[i].c=0;}add(tot,t,1,f[i].s);}int now=1; ll res=0;for (int i=1; i<=k; ++i){while (now<=q[i].x){add(s,++tot,m,0);for (int j=1; j<=n; ++j)if (id[j][now]) add(tot,id[j][now],inf,f[j].a);++now;}while (spfa()){int cur=t,low=inf;while (pre[cur]) low=min(low,edge[pre[cur]]),cur=ver[pre[cur]^1];res+=(ll)low*dist[t]; cur=t;while (pre[cur]) edge[pre[cur]]-=low,edge[pre[cur]^1]+=low,cur=ver[pre[cur]^1];}ans[q[i].id]=res;}for (int i=1; i<=k; ++i) write(ans[i]);flush();}
}int main()
{read(n);read(m);read(k);bool f1=1, f2=1;for (int i=1; i<=n; ++i){read(f[i].a),read(f[i].s),read(f[i].c),read(f[i].x);if (f[i].x) f1=0;if (f[i].s) f2=0;}for (int i=1; i<=k; ++i) read(q[i].x),q[i].id=i;sort(q+1,q+k+1);if (f1 && f2) solve1::G();else if (f1) solve2::G();else solve3::G();return 0;
}

并查集维护

#include<bits/stdc++.h>
#define mp make_pair
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=1e6+10,inf=1e5;char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{x=0;T f=1, ch=getchar();while (!isdigit(ch) && ch^'-') ch=getchar();if (ch=='-') f=-1, ch=getchar();while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();x*=f;
}char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x)
{if (!x) *fe++=48;if (x<0) *fe++='-', x=-x;T num=0, ch[20];while (x) ch[++num]=x%10+48, x/=10;while (num) *fe++=ch[num--];*fe++='\n';
}typedef int iarr[maxn];
iarr a,s,c,x,fa,num;
inline int get(int x)
{return fa[x]==x?x:fa[x]=get(fa[x]);
}ll ans[maxn];
priority_queue<pii>q;
int main()
{int n,m,k;read(n);read(m);read(k);for (int i=1; i<=n; ++i) read(a[i]),read(s[i]),read(c[i]),read(x[i]),q.push(mp(a[i]+s[i],i));for (int i=1; i<=inf; ++i) fa[i]=i,num[i]=m;int cnt=0,day;while (!q.empty()){int profit=q.top().first,t=q.top().second;q.pop();if (!x[t]) day=get(inf);else day=get(min(inf,(c[t]-1)/x[t]+1));if (!day) continue;--c[t],--num[day],++cnt;if (!num[day]) fa[day]=get(day-1);if (c[t]) q.push(mp(a[t],t));ans[cnt]=ans[cnt-1]+profit;}for (int i=1,p; i<=k; ++i) read(p),write(ans[min(cnt,m*p)]);flush();return 0;
}

堆维护

#include<bits/stdc++.h>
#define mp make_pair
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=1e5+10,inf=1e5;char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{x=0;T f=1, ch=getchar();while (!isdigit(ch) && ch^'-') ch=getchar();if (ch=='-') f=-1, ch=getchar();while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();x*=f;
}char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x)
{if (!x) *fe++=48;if (x<0) *fe++='-', x=-x;T num=0, ch[20];while (x) ch[++num]=x%10+48, x/=10;while (num) *fe++=ch[num--];*fe++='\n';
}pii Stack[maxn];int top,sum;
typedef int iarr[maxn];
iarr a,s,c,x,num;
bool vis[maxn];
ll ans[maxn];
vector<int>d[maxn];
priority_queue<pii>Q;
int main()
{int n,m,k;read(n);read(m);read(k);for (int i=1; i<=n; ++i) read(a[i]),read(s[i]),read(c[i]),read(x[i]);for (int i=1; i<=n; ++i)if (!x[i]) d[inf].push_back(i);else d[min(inf,(c[i]+x[i]-1)/x[i])].push_back(i);for (int i=inf; i; --i){for (int j=0; j<d[i].size(); ++j) Q.push(mp(a[d[i][j]]+s[d[i][j]],d[i][j]));if (Q.empty()) continue;for (int j=m; j && !Q.empty(); ){int profit=Q.top().first,t=Q.top().second;Q.pop();if (!vis[t]){vis[t]=1;ans[inf]+=profit;++num[t], --j;if (c[t]>1) Q.push(mp(a[t],t));}else{int rest=min(j,c[t]-num[t]-(i-1)*x[t]);ans[inf]+=1ll*rest*profit;num[t]+=rest, j-=rest;if (num[t]^c[t]) Stack[++top]=mp(a[t],t);}}while (top) Q.push(Stack[top--]);}while (!Q.empty()) Q.pop();for (int i=1; i<=n; ++i) sum+=num[i];for (int i=1; i<=n; ++i)if (num[i]==1) Q.push(mp(-s[i]-a[i],i));else if (num[i]) Q.push(mp(-a[i],i));for (int i=inf-1; i; --i){ans[i]=ans[i+1];while (sum>i*m && !Q.empty()){int profit=Q.top().first,t=Q.top().second;Q.pop(); profit*=-1;if (num[t]>1){int rest=min(sum-i*m,num[t]-1);num[t]-=rest, sum-=rest, ans[i]-=1ll*rest*profit;if (num[t]==1) Q.push(mp(-a[t]-s[t],t));else Q.push(mp(-a[t],t));}else --sum, --num[t], ans[i]-=profit;}}for (int i=1,p; i<=k; ++i) read(p),write(ans[p]);flush();return 0;
}

转载于:https://www.cnblogs.com/G-hsm/p/11348128.html

BZOJ 4946: [Noi2017]蔬菜 模拟费用流相关推荐

  1. BZOJ 5326 [JSOI2017]博弈 (模拟费用流、线段树)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=5326 题解 终于成为第8个A掉这题的人--orz tzw神仙早我6小时 本以为这东西常数 ...

  2. 【贪心+堆/模拟费用流增广】BZOJ4946 [NOI2017]蔬菜

    一道思路很好的题,因为篇幅太长赶时间,以下多数转自这里 [题目] 定义了一种蔬菜为: a i , s i , c i , x i a_i,s_i,c_i,x_i ai​,si​,ci​,xi​,有 n ...

  3. BZOJ 1920 Luogu P4217 [CTSC2010]产品销售 (模拟费用流、线段树)

    题目链接 (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=1920 (luogu) https://www.luogu.org/prob ...

  4. BZOJ 3836 Codeforces 280D k-Maximum Subsequence Sum (模拟费用流、线段树)

    题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=3836 (Codeforces) http://codeforces.com ...

  5. BZOJ 4849 [NEERC2016] Mole Tunnels (模拟费用流)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=4849 题解 其实也是模拟费用流,但是这道题和一般的题目不一样,这道题是在一个完全二叉树上 ...

  6. BZOJ 4849 [NEERC2016]Mole Tunnels (模拟费用流)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=4849 题解 其实也是模拟费用流,但是这道题和一般的题目不一样,这道题是在一个完全二叉树上 ...

  7. UOJ #455 [UER #8]雪灾与外卖 (贪心、模拟费用流)

    题目链接 http://uoj.ac/contest/47/problem/455 题解 模拟费用流,一个非常神奇的东西. 本题即为WC2019 laofu的讲课中的Problem 8,经典的老鼠进洞 ...

  8. P6122-[NEERC2016]Mole Tunnels【模拟费用流】

    正题 题目链接:https://www.luogu.com.cn/problem/P6122 题目大意 给出nnn个点的一棵满二叉树,每个点有容量cic_ici​,mmm次从pip_ipi​处加一只仓 ...

  9. [NOI2019] 序列(模拟费用流)

    原先自己想的建图: 正确建图: 但是 n 太大了,所以考虑模拟费用流: 注意: 在1中, 若选的两个位置相同,则为情况2,不用减 f: 若选的位置在另一序列中已被选,则为情况3或4,不用减 f: 若选 ...

最新文章

  1. 致广州达到信息技术有限公司
  2. 遇到 400、500 错误千万不要慌!
  3. Oracle cursor_sharing 参数 详解
  4. android文件管理实现所应用到的技术,基于Android的文件管理系统的设计与实现
  5. oracle常用命令收集
  6. 上位机与1200组态步骤_组态王与 I/O 设备
  7. linux远程执行迷路,linux操作系统基础
  8. STM32的学习记录--1.准备工作
  9. Maxwell核心新技术VXGI,MFAA测试
  10. 未了(endless)(【CCF】NOI Online 能力测试2 入门组第一题 )
  11. 图像局部特征(十)--BRIEF描述子
  12. CDMA2000中的Walsh码,PN码,短码序列的初相位偏置(PN OFFSET)之間的差別與關係(1)
  13. 蒙特卡洛—赌博模型笔记
  14. 如何创建苹果开发者个人号账号P8证书
  15. 计算神经科学简介~【整理自】类脑计算背后的计算神经科学框架
  16. 文樾杰出五金交电进销存管理系统 v6.12 下载
  17. 计算机考证上传照片说明
  18. 深入解读云场景下的网络抖动
  19. svn造成桌面图标显示问号的处理办法
  20. 如何查看主机的网卡MAC地址及含义

热门文章

  1. Ai智能对话页面html,js人工智能对话框 - osc_q50is30g的个人空间 - OSCHINA - 中文开源技术交流社区...
  2. Winform Panel设置颜色、宽度
  3. Angular4的双向数据绑定
  4. UML知识点总结(一)
  5. python保存不了_python文件无法保存怎么解决
  6. apple pay 技术_如何在Apple Watch上设置和使用Apple Pay
  7. 企业网站怎么制作?企业网站制作,只需记住这8个步骤
  8. 【数据结构-源码分析】HashMap源码分析(超级详细)
  9. 数据结构算法 - ConcurrentHashMap 源码解析
  10. 网络接口层协议:ATM