1015 德才論(超時)
阿新 • • 發佈:2022-03-31
前言
zkw真滴快!
題目
講解
剛開始思考這道題的時候,我試圖解決乾淨餐巾->髒餐巾 和 髒餐巾->乾淨餐巾的轉移,發現不會,於是自閉。
顯然我們不能把乾淨餐巾和髒餐巾混為一談,所以我們拆點,可以視作將一天拆為早上與晚上,早上收到乾淨餐巾並使用餐巾,晚上獲得髒餐巾,洗餐巾可以轉移到某一天的早上。
那麼我們怎麼強制早上使用餐巾並轉移到晚上呢?
拆一下,我們可以看成是早上一定要使用乾淨餐巾,晚上一定要獲得髒餐巾。
所以我們可以直接從早上向匯點連邊,表示使用餐巾,源點向晚上連邊表示獲得餐巾。
剩下的連邊就很好解決了。
- 早上向匯點連邊,表示使用餐巾。
- 源點向晚上連邊,表示獲得餐巾。
- 匯點向早上連邊,表示購買餐巾。
- 頭天晚上向下一天晚上連邊,表示懶狗不想洗餐巾。
- 晚上向某個白天連邊,表示洗餐巾。
如果用多路增廣的 zkw費用流,可以直接把 \(N\le 2\times 10^5\) 的加強版衝過去,加強版的正解應該是我之前思考的討論+二分/三分,這裡不做拓展。
程式碼
加強版
//12252024832524 #include <bits/stdc++.h> #define TT template<typename T> using namespace std; typedef long long LL; const int MAXN = 400005; const int INF = 0x3f3f3f3f; int days,p,qd,qc,sd,sc;//quick days; quick cost; slow.. LL Read() { LL x = 0,f = 1;char c = getchar(); while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();} return x * f; } TT void Put1(T x) { if(x > 9) Put1(x/10); putchar(x%10^48); } TT void Put(T x,char c = -1) { if(x < 0) putchar('-'),x = -x; Put1(x); if(c >= 0) putchar(c); } TT T Max(T x,T y){return x > y ? x : y;} TT T Min(T x,T y){return x < y ? x : y;} TT T Abs(T x){return x < 0 ? -x : x;} int head[MAXN],tot = 1,cur[MAXN]; struct edge{ int v,w,c,nxt; }e[MAXN<<3]; void Add_Edge(int u,int v,int w,int c){ e[++tot] = edge{v,w,c,head[u]}; head[u] = tot; } void Add_Double_Edge(int u,int v,int w,int c){ Add_Edge(u,v,w,c); Add_Edge(v,u,0,-c); } int dis[MAXN],maxflow; LL mincost; bool inq[MAXN],vis[MAXN]; bool bfs(int S,int T){ for(int i = 1;i <= T;++ i) dis[i] = INF; queue<int> q; q.push(S); dis[S] = 0; while(!q.empty()){ int x = q.front(); q.pop(); inq[x] = 0; for(int i = head[x],v; i ;i = e[i].nxt) if(e[i].w && dis[x] + e[i].c < dis[v = e[i].v]){ dis[v] = dis[x] + e[i].c; if(!inq[v]) inq[v] = 1,q.push(v); } } return dis[T] < INF; } int dfs(int x,int flow,int T){ if(x == T) return flow; int ret = 0; vis[x] = 1; for(int &i = cur[x],v; i ;i = e[i].nxt) if(e[i].w && dis[x] + e[i].c == dis[v = e[i].v] && !vis[v]){ int dz = dfs(v,Min(flow-ret,e[i].w),T); e[i].w -= dz; e[i^1].w += dz; if((ret += dz) == flow) break; } vis[x] = 0; return ret; } void MFMC(int S,int T){ while(bfs(S,T)){ for(int i = 1;i <= T;++ i) cur[i] = head[i]; int ret = dfs(S,INF,T); maxflow += ret; mincost += 1ll * ret * dis[T]; } } int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); days = Read(); qd = Read(); sd = Read(); qc = Read(); sc = Read(); p = Read(); int S = days<<1|1,T = S+1,sx = days<<1; for(int i = 1;i <= days;++ i){ int nd = Read(),day = (i<<1)-1,night = day+1; Add_Double_Edge(day,T,nd,0);//use napkins Add_Double_Edge(S,night,nd,0);//gain dirty napkins Add_Double_Edge(S,day,INF,p);//purchase if(night+2 <= sx) Add_Double_Edge(night,night+2,INF,0);//lazy dog if(day+(qd<<1) <= sx) Add_Double_Edge(night,day+(qd<<1),INF,qc);//quick wash if(day+(sd<<1) <= sx) Add_Double_Edge(night,day+(sd<<1),INF,sc);//slow wash } MFMC(S,T); Put(mincost,'\n'); return 0; }