P1164 小A点菜
标签
进入讨论版
相关讨论
推荐题目
题目背景
uim
神犇拿到了uoi
的ra
(镭牌)后,立刻拉着基友小A
到了一家……餐馆,很低端的那种。
uim
指着墙上的价目表(太低级了没有菜单),说:“随便点”。
题目描述
不过uim
由于买了一些辅(e)辅(ro)书
,口袋里只剩MMM元(M≤10000)(M \le 10000)(M≤10000)。
餐馆虽低端,但是菜品种类不少,有NNN种(N≤100)(N \le 100)(N≤100),第iii种卖aia_iai元(ai≤1000)(a_i \le 1000)(ai≤1000)。由于是很低端的餐馆,所以每种菜只有一份。
小A
奉行“不把钱吃光不罢休”,所以他点单一定刚好吧uim
身上所有钱花完。他想知道有多少种点菜方法。
由于小A
肚子太饿,所以最多只能等待111秒。
输入格式
第一行是两个数字,表示N和M。
第二行起N个正数ai(可以有相同的数字,每个数字均在1000以内)。
输出格式
一个正整数,表示点菜方案数,保证答案的范围在int之内。
输入输出样例
输入 #1
4 4 1 1 2 2
输出 #1
3
思路:
用f[i][j]来表示取到第i个物品、有j块钱能吃到的方案数。
在每次转移时,有三种情况:
1、j == w[i], 此时f[i][j]等于选了i-1件的有j块钱的方案数+1.
2、j > w[i], 此时由于钱是富足的,所以可以拿f[i-1][j]+f[i-1][j-w[i]]的方案数
3、j < w[i], 此时由于钱不够了,所以拿不了,方案数为f[i-1][j].
因为和上一个物品状态关联不大。题解把三个情况总结到一起了,方程写成了f[j-w[i]],在nm比较大的时候可以用上。
1 #include <bits/stdc++.h> 2 #define dbg(x) cout << #x << "=" << x << endl 3 4 using namespace std; 5 typedef long long LL; 6 const int maxn = 100 + 7; 7 8 int f[maxn][10007]; 9 int w[maxn]; 10 11 namespace _buff { 12 13 const size_t BUFF = 1 << 19; 14 char ibuf[BUFF], *ib = ibuf, *ie = ibuf; 15 char getc() { 16 if (ib == ie) { 17 ib = ibuf; 18 ie = ibuf + fread(ibuf, 1, BUFF, stdin); 19 } 20 return ib == ie ? -1 : *ib++; 21 } 22 23 } 24 25 int read() { 26 using namespace _buff; 27 int ret = 0; 28 bool pos = true; 29 char c = getc(); 30 for (; (c < '0' || c > '9') && c != '-'; c = getc()) { 31 assert(~c); 32 } 33 if (c == '-') { 34 pos = false; 35 c = getc(); 36 } 37 for (; c >= '0' && c <= '9'; c = getc()) { 38 ret = (ret << 3) + (ret << 1) + (c ^ 48); 39 } 40 return pos ? ret : -ret; 41 } 42 43 int main() 44 { 45 int n,m; 46 scanf("%d %d",&n,&m); 47 for(int i = 1; i <= n; ++i) { 48 scanf("%d",&w[i]); 49 } 50 int ans = 0; 51 for(int i = 1; i <= n; i++) { 52 for(int j = 0; j <= m; j++) { 53 if(j == w[i]) { 54 f[i][j] = f[i-1][j] + 1; 55 } 56 else if(j > w[i]) { 57 f[i][j] = f[i-1][j] + f[i-1][j-w[i]]; 58 } 59 else if(j < w[i]) { 60 f[i][j] = f[i-1][j]; 61 } 62 } 63 } 64 65 printf("%d\n",f[n][m]); 66 return 0; 67 }