饭票 (bticket.pas)
学校的食堂在使用饭卡之前使用饭票
饭票并不向饭卡一样方便。比如你有1张5元饭票和3张1元饭票,则你无法付4元的饭费。
某天小x去食堂吃饭,手里有n种饭票,面值分别为A1~An,数量分别为C1~Cn
请你计算小x的饭票能组成多少在[1,m]区间内的面值。
Input (bticket.in)
第一行2个数n m,用空格隔开。
以后n个数,分别为A1..An
以后n个数,分别为C1..Cn
Output (bticket.out)
一个数,即问题的答案
Sample
INPUT |
OUTPUT |
3 10 1 2 4 2 1 1 |
8 |
约定
1 ≤ n ≤ 100
1 ≤ Ai ≤ m ≤ 100000
1 ≤ Ci ≤ 1000
不看数据范围的话,就会认为纯属水题一道!看了范围后,便会发现还有很有做的价值。
很容易想到的是O(n*m*Cmax)的算法,但是这只有50分!
于是乎,我们必须从循环过程中着手,简化算法。
我是用
在使用背包的时候,很多步骤是重复的......所以很慢.....
看了一牛的题解后http://www.cppblog.com/liaorc/articles/41598.html
突然有了启发:
完全可以像最大升序数列那样做!
记录最少要用多少Ai达到f[j],然后在循环的过程中更新!
这样就可以把循环压缩到O(m*n)!
代码如下:
1 var count,g,h,t,i,j,n,m,max:longint;a,b:array[0..101]of longint;
2 v:array[0..110001]of boolean;
3 f:array[0..110001]of longint;
4 begin
5 assign(input,'bticket.in');reset(input);
6 assign(output,'bticket.out');rewrite(output);
7 readln(n,m);
8 for i:=1 to n do
9 begin
10 read(a[i]);
11 end;
12 for i:=1 to n do
13 begin
14 read(b[i]);
15 end;
16 max:=0;
17 fillchar(v,sizeof(v),0);
18 v[0]:=true;
19 for i:=1 to n do
20 begin
21 fillchar(f,sizeof(f),0);
22 for h:=0 to m do
23 begin
24 if h+a[i]>m then break;
25 if v[h] then
26 begin
27 if f[h]<b[i] then
28 begin
29 if not(v[h+a[i]]) then
30 begin
31 v[h+a[i]]:=true;
32 f[h+a[i]]:=f[h]+1;
33 end
34 else
35 begin
36 if f[h+a[i]]>f[h]+1 then
37 begin
38 f[h+a[i]]:=f[h]+1;
39 end;
40 end;
41
42 end;
43 end;
44 end;
45 end;
46 count:=0;
47 for i:=1 to m do
48 begin
49 if v[i] then inc(count);
50 end;
51 writeln(count);
52 close(input);close(output);
53 end.
2 v:array[0..110001]of boolean;
3 f:array[0..110001]of longint;
4 begin
5 assign(input,'bticket.in');reset(input);
6 assign(output,'bticket.out');rewrite(output);
7 readln(n,m);
8 for i:=1 to n do
9 begin
10 read(a[i]);
11 end;
12 for i:=1 to n do
13 begin
14 read(b[i]);
15 end;
16 max:=0;
17 fillchar(v,sizeof(v),0);
18 v[0]:=true;
19 for i:=1 to n do
20 begin
21 fillchar(f,sizeof(f),0);
22 for h:=0 to m do
23 begin
24 if h+a[i]>m then break;
25 if v[h] then
26 begin
27 if f[h]<b[i] then
28 begin
29 if not(v[h+a[i]]) then
30 begin
31 v[h+a[i]]:=true;
32 f[h+a[i]]:=f[h]+1;
33 end
34 else
35 begin
36 if f[h+a[i]]>f[h]+1 then
37 begin
38 f[h+a[i]]:=f[h]+1;
39 end;
40 end;
41
42 end;
43 end;
44 end;
45 end;
46 count:=0;
47 for i:=1 to m do
48 begin
49 if v[i] then inc(count);
50 end;
51 writeln(count);
52 close(input);close(output);
53 end.
测试结果如下
<?xml version="1.0" ?>
- <cena version="0.6.3">
- <result judgetime="40109.7472578472">
- <problem title="bticket" filename="bticket.pas" status="1" hash="2414061685" detail="">