题目大意
思路
我觉得正常人的第一反应应该就是dp了吧,但是,实际上,它会超时,而且是开了
O
(
2
)
O(2)
O(2)都A不了的那种超时,所以我们得换一个思路。但是,好像,如果没有限制的话,这不就是一个TMD 完全背包问题么?dp式连我这种蒟蒻都会秒列出
d
p
[
i
]
=
∑
j
=
1
4
d
p
[
i
−
c
[
j
]
]
dp[i]=\sum_{j=1}^{4}dp[i-c[j]]
dp[i]=∑j=14dp[i−c[j]],好,我们还是一个一个地搞吧,
如果半毛钱限制都没有,那么,答案就是
d
p
[
s
]
dp[s]
dp[s],如果只有一个限制,那么,答案就是
d
p
[
s
]
−
d
p
[
s
−
c
[
1
]
×
(
d
[
1
]
+
1
)
]
dp[s]-dp[s-c[1]\times (d[1]+1)]
dp[s]−dp[s−c[1]×(d[1]+1)],为哈子是这个玩意呢?这里的
s
−
c
[
1
]
×
(
d
[
1
]
+
1
)
s-c[1]\times (d[1]+1)
s−c[1]×(d[1]+1)就是说对于第一种硬币,我取了超过限制个,然后意会一下估计就能意会到了。好,我们现在有一个的了,我们按照老土套路,我们可以看出这个就是容斥原理,那么,对于两种的情况,就该是
d
p
[
s
]
−
d
p
[
s
−
c
[
1
]
×
(
d
[
1
]
+
1
)
−
c
[
2
]
×
(
d
[
2
]
+
1
)
]
dp[s]-dp[s-c[1]\times (d[1]+1)-c[2]\times (d[2]+1)]
dp[s]−dp[s−c[1]×(d[1]+1)−c[2]×(d[2]+1)],对于三个的情况,就应该是
d
p
[
s
−
∑
i
=
1
3
c
[
i
]
×
(
d
[
i
]
+
1
)
]
dp[s-\sum_{i=1}^{3}c[i]\times (d[i]+1)]
dp[s−∑i=13c[i]×(d[i]+1)],然后以此类推四个的情况,然后,一共有
2
4
2^4
24种情况(每个点越界或不越界),我们可以用优美的位运算来完成这个东西,就是一个容斥模板,代码附上,时间复杂度:
O
(
4
×
100000
+
2
4
×
t
o
t
)
O(4\times 100000+2^4\times tot)
O(4×100000+24×tot)
代码
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define Int register int
#define int long long
#define MAXN 100005
int tot,c[5],dp[MAXN];
void init()
{
dp[0] = 1;
for (Int i = 1;i <= 4;++ i)
for (Int j = c[i];j <= MAXN - 5;++ j)
dp[j] += dp[j - c[i]];
}
void read (int &x)
{
x = 0;char c = getchar();int f = 1;
while(c < '0' || c > '9'){if(c == '-')f = -f;c = getchar();}
while(c >= '0' && c <= '9'){x = (x << 3) + (x << 1) + c - '0';c = getchar();}
x *= f;return ;
}
void write (int x)
{
if (x < 0){x = -x;putchar('-');}
if (x > 9) write (x / 10);
putchar (x % 10 + '0');
}
signed main()
{
for (Int i = 1;i <= 4;++ i) read (c[i]);
read (tot);
init();
while (tot --)
{
int d[5] = {},s;
for (Int i = 1;i <= 4;++ i) read (d[i]);
read (s);
int ans = 0;
for (Int i = 0;i <= 15;++ i)
{
int cnt = 0;
int tot = s;
for (Int j = 1;j <= 4;++ j)
if ((i >> j - 1) & 1)
{
tot -= c[j] * (d[j] + 1);
cnt ^= 1;
}
if (tot < 0) continue;
ans += (cnt == 0 ? 1 : -1) * dp[tot];
}
write (ans),putchar ('\n');
}
return 0;
}