CF802C Heidi and Library

CF802C Heidi and Library

题目描述:

Link

题目分析:

看到这么小的数据范围直接想网络流(其实一开始想的搜索),看到题目中还有一个价值的限制,那么往费用流上面去想。

那么难点又来到了建图上,那么问题的难点就是如何去处理丢去那一本书架里面的书的问题。

我们可以发现一些性质:

如果 \(i\) 天和 \(j\) 天都用了同一本书,那么如果中间没有扔掉,那么只需要花费一本书的价格,反之要再买一次即花费两本书的价钱。那么假设我们在中间需要扔掉这本书的话,我们完全可以在 \(i\) 处卖掉,这样是完全不劣的。

那么利用费用流去解决这么一个每一天买还是不买的问题是非常的复杂的。所以说我们直接先把所有的书都买一遍,利用费用流去看某些书树不需要进行购买的。

那么如果说 \(i\) 天买的书留到了 \(j\) 天,那么我们可以在 \(j-1\) 卖掉这本书,那么其实就可以看成在 \(j\) 天没有买书。

那么我们的模型就显现出来了。大致可以分为以下几步。

  1. 每一天都有两个节点 \(i\)\(i’\),从源点向每一天的 \(i\) 进行连容量为 1,边权是书的价格的边,表示这一天买了这本书。
  2. 每一个 \(i\)\(i’\) 连一条容量为 1,费用为 0 的边,表示今天买完之后直接就卖掉了。
  3. 每一个 \(i\)\(i+1\) 连一条容量为 \(k-1\),费用为 0 的边,表示书的容量,书架最多能承受 \(k-1\) 本书。
  4. 每一个 \(i-1\)\(i\) 所拥有的书的种类的上一个点连一个容量为 1,边权为负的价格的边,表示卖掉这本书
  5. 每一个 \(i'\) 向汇点连容量为 1,费用为 0 的边来统计扔的答案。

最后跑一边费用流即可。(建图真神奇

#include<bits/stdc++.h>
#define g() getchar()
#define il inline
#define eps 1e-10
#define LL long long
#define pa pair<int, int>
#define for_1(i, n) for(int i = 1; i <= (n); ++i)
#define for_0(i, n) for(int i = 0; i < (n); ++i)
#define for_xy(i, x, y) for(int i = (x); i <= (y); ++i)
#define for_yx(i, y, x) for(int i = (y); i >= (x); --i)
#define for_edge(i, x) for(int i = head[x]; i; i = nxt[i])
// #define int long long
#define DB double
#define m_p make_pair
#define p_b push_back
#define fir first
#define sec second
// #define mid ((l + r) >> 1)
using namespace std;
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1000000007;
const int up = 259;

inline int re() {
	int x = 0, p = 1;
	char ch = getchar();
	while(ch > '9' || ch < '0') {if(ch == '-') p = -1; ch = getchar();}
	while(ch <= '9' and ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
	return x * p;
}

int head[N], ver[N], edge[N], tot = 1, nxt[N], cost[N];
il void add(int x, int y, int z, int co) {ver[++tot] = y; nxt[tot] = head[x]; head[x] = tot; edge[tot] = z; cost[tot] = co; }
il void addedge(int x, int y, int z, int co ) {add(x, y, z, co); add(y, x, 0, -co); }
//n^2 m 
int n, m, s, t, mincost, maxflow, k; 
int vis[N], incf[N], dis[N], pre[N]; 
queue<int> q; 
int a[N], b[N];

bool spfa() {
	memset(vis, 0, sizeof(vis)); 
	memset(dis, 0x3f, sizeof(dis)); 
	while(q.size()) q.pop(); 
	q.push(s); incf[s] = 1LL<<30; vis[s] = 1; dis[s] = 0; 
	while(q.size()) {
		int x = q.front(); q.pop(); vis[x] = 0; 
		for_edge(i, x) {
			int y = ver[i], z = edge[i], co = cost[i];
			if(dis[y] > dis[x] + co and z) {
				incf[y] = min(incf[x], z); 
				dis[y] = dis[x] + co;  pre[y] = i; 
				if(!vis[y]) q.push(y); 
			}
		}
	}
	return dis[t] != INF; 
}
il void ML() {
	while(spfa()) {
		maxflow += incf[t]; mincost += incf[t] * dis[t]; 
		int x = t; 
		while(x) {
			int i = pre[x]; 
			edge[i] -= incf[t]; edge[i ^ 1] += incf[t]; 
			x = ver[i ^ 1]; 
		}
	}
}

signed main() {
    n = re(), k = re(); for_1(i, n) a[i] = re(); for_1(i, n) b[i] = re();  s = 2 * n + 1; t = s + 1; 
    for_1(i, n) addedge(s, i, 1, b[a[i]]);  for_1(i, n) addedge(i, i + n, 1, 0); 
    for(int i = 1; i < n; ++i) addedge(i, i + 1, k - 1, 0); 
    for(int i = 2; i <= n; ++i) {
        for(int j = i - 1; j >= 1; --j) {
            if(a[j] == a[i]) {addedge(i - 1, j + n, 1, -b[a[i]]); break; }
        }
    }
    for(int i = 1; i <= n; ++i) addedge(i + n, t, 1, 0); ML(); 
    cout<<mincost<<endl; 
}
posted @ 2022-04-09 16:38  Zwaire  阅读(55)  评论(0)    收藏  举报