找钱
时间限制: 1 Sec 内存限制: 128 MB
题目描述
小 L L L 所在的 L L L 国由于没有普及移动支付,依然在大规模使用纸币。一共有 n n n 种面值的纸币,面值互不相同。一天小 L L L 去商店购买一个价格为 X X X 元的物品,他提前知道了自己手里和店员手里每种面值的纸币的数量,他想知道一共有多少种付钱-找钱的方式。两种付钱-找钱的方式不同,当且仅当存在一种面值,在两种方案中小 L L L 付出的该种面值的纸币数量不同或店员找的该种面值的纸币数量不同。此外,设小 L L L 付出的纸币面值总数为 Y Y Y,则小 L L L 付出的纸币中不能存在面值小于等于 Y − X Y-X Y−X 的纸币(不然就没有必要付这张纸币了)。
输入
第一行输入两个正整数
n
,
X
n,X
n,X,分别表示纸币面值的数量以及小
L
L
L 想要购买的商品的价格。
接下来
n
n
n 行每行三个整数
a
i
,
b
i
,
c
i
a_i,b_i,c_i
ai,bi,ci,分别表示第
i
i
i 种纸币的面值,小
X
X
X 拥有的该种纸币数量,店员拥有的该种纸币数量,保证面值
a
i
a_i
ai 单调增加。
输出
一行输出一个整数,表示总方案数对 1000000007 1000000007 1000000007 取模的结果。
样例输入
3 10
1 5 3
3 2 2
5 3 2
样例输出
5
提示
对于 100 100% 100 的数据, n ≤ 1000 , X , a i , b i , c i ≤ 10000 n≤1000,X,a_i,b_i,c_i≤10000 n≤1000,X,ai,bi,ci≤10000
思路
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示小
L
L
L 前
i
i
i 个货币构成
j
j
j 价值时的方案数。
g
[
i
]
[
j
]
g[i][j]
g[i][j] 表示店家前
i
i
i 个货币构成
j
j
j 价值时的方案数。
f
[
i
]
[
j
]
=
∑
k
=
0
b
[
i
]
f
[
i
+
1
]
[
j
−
k
×
a
[
i
]
]
(
j
<
X
+
a
[
i
]
)
f[i][j]=\sum\limits_{k=0}^{b[i]}{f[i+1][j-k×a[i]]}(j < X+a[i])
f[i][j]=k=0∑b[i]f[i+1][j−k×a[i]](j<X+a[i])
g
[
i
]
[
j
]
=
∑
k
=
0
c
[
i
]
g
[
i
+
1
]
[
j
−
k
×
a
[
i
]
]
(
j
<
m
a
x
(
a
[
i
]
)
)
g[i][j]=\sum\limits_{k=0}^{c[i]}{g[i+1][j-k×a[i]]}(j < max(a[i]))
g[i][j]=k=0∑c[i]g[i+1][j−k×a[i]](j<max(a[i]))
注意:
题目有额外限制条件:
Y
<
x
+
a
[
i
]
Y<x+a[i]
Y<x+a[i];
所以为了满足扩展时所用到的上一种货币的状态中都满足,就需要从大到小计算。
时限也很恶心。。。
取模可以优化
#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <algorithm>
#include <unordered_map>
#include <vector>
using namespace std;
#define ls (rt<<1)
#define rs (rt<<1|1)
typedef long long ll;
template <typename T>
inline void read(T &x) {
x = 0;
static int p;
p = 1;
static char c;
c = getchar();
while (!isdigit(c)) {
if (c == '-')p = -1;
c = getchar();
}
while (isdigit(c)) {
x = (x << 1) + (x << 3) + (c - 48);
c = getchar();
}
x *= p;
}
template <typename T>
inline void print(T x) {
if (x<0) {
x = -x;
putchar('-');
}
static int cnt;
static int a[50];
cnt = 0;
do {
a[++cnt] = x % 10;
x /= 10;
} while (x);
for (int i = cnt; i >= 1; i--)putchar(a[i] + '0');
puts("");
}
const double pi=acos(-1);
const double eps=1e-6;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
const int maxn = 1010;
int n,x;
int a[maxn],b[maxn],c[maxn];
int f[maxn][maxn*20],g[maxn][maxn*10];
int mx;
inline void work() {
read(n);
read(x);
for (int i = 1; i <= n; i++) {
read(a[i]);
read(b[i]);
read(c[i]);
mx = max(mx, a[i]);
}
f[n + 1][0] = 1;
g[0][0] = 1;
for (int i = n; i >= 1; --i) {
for (int j = 0; j - x < a[i]; ++j) {
for (int k = 0; k <= b[i] && k * a[i] <= j; ++k) {
f[i][j] += f[i + 1][j - k * a[i]];
if (f[i][j] > mod)f[i][j] = f[i][j] - mod;
}
}
for (int j = x + a[i]; j < x + mx; ++j)f[i][j] = f[i + 1][j];
}
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < mx; ++j) {
for (int k = 0; k <= c[i] && k * a[i] <= j; ++k) {
g[i][j] = g[i][j] + g[i - 1][j - k * a[i]];
if (g[i][j] > mod)g[i][j] = g[i][j] - mod;
}
}
}
ll ans = 0;
for (int j = x; j < x + mx; ++j) {
ans += 1ll * f[1][j] * g[n][j - x];
if (ans > mod)ans = ans % mod;
}
print(ans);
}
int main() {
//freopen("1.txt","r",stdin);
int T = 1;
//read(T);
while (T--) {
work();
}
return 0;
}