首页 > 代码库 > 2017-8-8 Summer:背包系列+斜率优化

2017-8-8 Summer:背包系列+斜率优化

A - 最大报销额(01背包)

现有一笔经费可以报销一定额度的发票。允许报销的发票类型包括买图书(A类)、文具(B类)、差旅(C类),要求每张发票的总额不得超过1000元,每张发票上,单项物品的价值不得超过600元。现请你编写程序,在给出的一堆发票中找出可以报销的、不超过给定额度的最大报销额。

Input

测试输入包含若干测试用例。每个测试用例的第1行包含两个正数 Q 和 N,其中 Q 是给定的报销额度,N(<=30)是发票张数。随后是 N 行输入,每行的格式为: m Type1:price1 Type2:price2 ... Type_m:price_m 其中正整数 m 是这张发票上所开物品的件数,Type_i 和 price_i 是第 i 项物品的种类和价值。物品种类用一个大写英文字母表示。当N为0时,全部输入结束,相应的结果不要输出。

Output

对每个测试用例输出1行,即可以报销的最大数额,精确到小数点后2位。

Sample Input

200.00 32 A:23.50 B:100.001 C:650.003 A:59.99 A:120.00 X:10.001200.00 22 B:600.00 A:400.001 C:200.501200.50 32 B:600.00 A:400.001 C:200.501 A:100.00100.00 0

Sample Output

123.501000.001200.50

Solve:

先预处理出所有可以使用的发票,然后最大报销额度就是背包的最大容量,每张发票就是物品的重量,然后就是简化版的01背包问题了

Code:

技术分享
 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define CLR0(x) memset(x , 0 , sizeof(x)) 4 static const int MAXN = 30 * 1000 * 100 + 10; 5 typedef long long ll; 6 int n; 7 double mx; 8 int bg[MAXN] , dp[MAXN]; 9 int index;10 int main()11 {12     while(~scanf("%lf%d" , &mx , &n) && n)13     {14         index = 0;15         CLR0(dp);16         ll mxv = mx * 100;17         for(int i = 1 ; i <= n ; ++i)18         {19             bool flag = 1;20             int m;21             scanf("%d" , &m);22             double a = 0 , b = 0 , c = 0;23             for(int i = 1 ; i <= m ; ++i)24             {25                 double my;26                 char ty;27                 scanf(" %c:%lf" , &ty  ,&my);28                 if(ty == A) a += my;29                 else if(ty == B) b += my;30                 else if(ty == C) c += my;31                 else flag = 0;32             }33             if(a + b + c <= 1000 && flag && a <= 600 && b <= 600 && c <= 600)34                 bg[++index] = (a + b + c) * 100;35         }36         for(int i = 1 ; i <= index ; ++i)37         {38             for(ll j = mxv ; j >= bg[i] ; --j)39                 dp[j] = max(dp[j] , dp[j - bg[i]] + bg[i]);40 41         }42         printf("%.2f\n" , dp[mxv] / 100.0);43     }44 }
View Code

B - Writing Code(完全背包)

Programmers working on a large project have just received a task to write exactly mlines of code. There are n programmers working on a project, the i-th of them makes exactly a**i bugs in every line of code that he writes.

Let‘s call a sequence of non-negative integers v1, v2, ..., v**n a plan, if v1 + v2 + ... + v**n = m. The programmers follow the plan like that: in the beginning the first programmer writes the first v1 lines of the given task, then the second programmer writes v2 more lines of the given task, and so on. In the end, the last programmer writes the remaining lines of the code. Let‘s call a plan good, if all the written lines of the task contain at most b bugs in total.

Your task is to determine how many distinct good plans are there. As the number of plans can be large, print the remainder of this number modulo given positive integermod.

Input

The first line contains four integers n, m, b, mod (1 ≤ n, m ≤ 500, 0 ≤ b ≤ 500; 1 ≤ mod ≤ 109 + 7) — the number of programmers, the number of lines of code in the task, the maximum total number of bugs respectively and the modulo you should use when printing the answer.

The next line contains n space-separated integers a1, a2, ..., a**n (0 ≤ a**i ≤ 500) — the number of bugs per line for each programmer.

Output

Print a single integer — the answer to the problem modulo mod.

Example

Input

3 3 3 1001 1 1

Output

10

Input

3 6 5 10000000071 2 3

Output

0

Input

3 5 6 111 2 1

Output

0

Means:

要求写?行程序,现在有n个程序员,每个程序员写一行代码的bug数为?,现在要求总的bug数不超过b,问你有多少种方案,方案数模mod

Solve:

?表示写i行代码,bug数量为j个的方案数,?,这两维就是个完全背包(因为每个人可以写多行),然后枚举每个人,枚举行数,再枚举bug数量

Code:

技术分享
 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define CLR0(x) memset(x , 0 , sizeof(x)) 4 static const int MAXN = 666; 5 typedef long long ll; 6 int n , m , b , mod; 7 int bug[MAXN]; 8 ll dp[MAXN][MAXN]; 9 10 int main()11 {12     while(~scanf("%d%d%d%d" , &n , &m , &b , &mod))13     {14         for(int i = 1 ; i <= n ; ++i)15         {16             scanf("%d" , bug + i);17         }18         CLR0(dp);19         dp[0][0] = 1;20         for(int i = 1 ; i <= n ; ++i)21         {22             for(int j = 1 ; j <= m ; ++j)23             {24                 for(int k = bug[i] ; k <= b ; ++k)25                 {26                     dp[j][k] = (dp[j - 1][k - bug[i]] + dp[j][k]) % mod;27                 }28             }29         }30         ll sum = 0;31         for(int i = 0 ; i <= b ; ++i)32             sum = (sum + dp[m][i]) % mod;33         printf("%lld\n" , sum);34     }35 }
View Code

 

2017-8-8 Summer:背包系列+斜率优化