Link
看到这么小的数据范围直接想网络流(其实一开始想的搜索),看到题目中还有一个价值的限制,那么往费用流上面去想。
那么难点又来到了建图上,那么问题的难点就是如何去处理丢去那一本书架里面的书的问题。
我们可以发现一些性质:
如果 i 天和 j 天都用了同一本书,那么如果中间没有扔掉,那么只需要花费一本书的价格,反之要再买一次即花费两本书的价钱。那么假设我们在中间需要扔掉这本书的话,我们完全可以在 i 处卖掉,这样是完全不劣的。
那么利用费用流去解决这么一个每一天买还是不买的问题是非常的复杂的。所以说我们直接先把所有的书都买一遍,利用费用流去看某些书树不需要进行购买的。
那么如果说 i 天买的书留到了 j 天,那么我们可以在 j−1 卖掉这本书,那么其实就可以看成在 j 天没有买书。
那么我们的模型就显现出来了。大致可以分为以下几步。
- 每一天都有两个节点 i 和 i′,从源点向每一天的 i 进行连容量为 1,边权是书的价格的边,表示这一天买了这本书。
- 每一个 i 向 i′ 连一条容量为 1,费用为 0 的边,表示今天买完之后直接就卖掉了。
- 每一个 i 向 i+1 连一条容量为 k−1,费用为 0 的边,表示书的容量,书架最多能承受 k−1 本书。
- 每一个 i−1 向 i 所拥有的书的种类的上一个点连一个容量为 1,边权为负的价格的边,表示卖掉这本书
- 每一个 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 DB double
#define m_p make_pair
#define p_b push_back
#define fir first
#define sec second
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); }
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;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具