博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[BZOJ3312][USACO]不找零(状压DP)
阅读量:6578 次
发布时间:2019-06-24

本文共 2175 字,大约阅读时间需要 7 分钟。

Description

约翰带着 N 头奶牛在超市买东西,现在他们正在排队付钱,排在第 i 个位置的奶牛需要支付 Ci元。今天说好所有东西都是约翰请客的,但直到付账的时候,约翰才意识到自己没带钱,身上只有 K张消费卡,第 i 张卡里有 Vi 元余额。

问题是,这些消费卡都是一次性的,它们可以被收银机读取,但如果卡一旦离开了收银机,卡里的余额就会归零,而且超市也不负责找零!奶牛的队伍很长,不可能再调整她们的位置了,所以一张卡只能支付一段连在一起的账单。而且,一张账单只能用一张消费卡支付,超市的系统不接受用两张或以上的卡支付一笔账单。

约翰的问题就是按照什么样的顺序来使用这些消费卡,才能让他能为所有的奶牛买单,而且使得剩余的消费卡的余额之和最大呢?

Input Format

• 第一行:两个整数 K 和 N ,1 ≤ K ≤ 16, 1 ≤ N ≤ 10^5

• 第二行到第 K + 1 行:第 i + 1 行有一个整数 Vi,1 ≤ Vi ≤ 10^9

• 第 K + 2 行到第 K + N + 1 行:第 i + K + 1 行有一个整数 Ci,1 ≤ Ci ≤ 10^4

Output Format

单个整数:表示约翰买完所有奶牛的单之后,最多还能剩多少余额,如果他带的卡根本没有办法支付所有的账单,输出 −1。

Solution

发现K范围小,考虑状压DP,设\(F[S]\)表示所以消费卡状态为S时可以到达最后面的奶牛编号,即前面的奶牛都付完,

在二进制下1表示用过了,0表示没有

那么\(F[S|2^{k-1}]=max\{Get(card(k),F[S]+1)\}\) ,

\(Get(s,pos)\) 表示可用金额为s, 从\(Cow_{pos}\) 可到达最远的奶牛坐标,

那么Get函数可以用前缀和+二分查找优化,否则会超时

这题挂了好几次,

  1. 写了前缀和,后面忘记写二分查找
  2. 没有用max!WA了,居然还过了好多点

Code

#include 
#include
#define N 100010using namespace std;int n, k, card[19], sum[N], cow[N], f[1 << 19], Ans;inline int read() { int x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') {if (ch == '-')f = -1; ch = getchar();} while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();} return x * f;}inline int get(int k, int st) { int l = st, r = n, res; while (l <= r) { int mid = (l + r) >> 1; if (sum[mid] - sum[st - 1] <= k) res = mid, l = mid + 1; else r = mid - 1; } return res;}inline int cnt(int S) { int r = 0; for (int i = 1; i <= k; ++i) if (!(S & (1 << (i - 1)))) r += card[i]; return r;}int main() { k = read(), n = read(); for (int i = 1; i <= k; ++i) card[i] = read(); for (int i = 1; i <= n; ++i) { cow[i] = read(); sum[i] = sum[i - 1] + cow[i]; } Ans = -1; for (int S = 0; S < (1 << k); ++S) { if (f[S] == n) continue; for (int i = 1; i <= k; ++i) { int T = (1 << (i - 1)); if (S & T) continue; f[S | T] = max(f[S | T], get(card[i], f[S] + 1)); if (f[S | T] == n) Ans = max(Ans, cnt(S | T)); } } printf("%d\n", Ans); return 0;}

转载于:https://www.cnblogs.com/void-f/p/7738549.html

你可能感兴趣的文章
我的友情链接
查看>>
分区技术学习一
查看>>
Juniper 高级选项
查看>>
编程能力的四种境界
查看>>
编译安装mysql
查看>>
在windows上秒开应用程序
查看>>
【20180611】MySQL OOM
查看>>
memcached
查看>>
Python面向对象编程(一)
查看>>
决心书
查看>>
如何把图片上的文字转换成word?
查看>>
7z命令行
查看>>
C语言编程实现 输入一个非负整数,返回组成它的数字之和(递归方法)
查看>>
c3p0
查看>>
redis cluster 集群搭建(增、删、改、查) :5.0.2
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
引号-下划线,连接多个变量
查看>>
游戏LOGO它应该长什么样?
查看>>
我的友情链接
查看>>