P1450 [HAOI2008] 硬币购物 dp 容斥 —— s - c[i]*(d[i]+1)怎么理解

[HAOI2008] 硬币购物 - 洛谷

看了洛谷许多题解,一开始理解不了为什么是 s - c[i]*(d[i]+1),为什么要+1呢?

其实是dp理解的不好。

这里的意思就是该枚硬币先超过限制,接下来剩下的背包也要填满,4种硬币随便组合的情况数。

------------------

首先这些题解是假设4种硬币都无限的完全背包。

(dp[ i ] ,i指的钱数,dp值是情况数。)

然后我们思考,这四种硬币是组合的,也就是第一种的所有情况上加第二种的所有情况...

也就是dp[s]已经是四种硬币的组合的情况数了。

容斥定理会吧?(其实证明我也不会,这个大学离散数学里有,但是证明比较奇怪,我没有看懂)

因为四种硬币的数量并不是无限,所以我们上面的dp要减去不合理的。

1,2,3,4可能单独不合理,也可能若干个同时不合理,所以要用容斥定理来计算。(避免重复)

即减去1,2,3,4不合理的,加上12,13,14,23,24,34两个不合理的,减去3个不合理的,加上4个不合理的。

然后就是不合理的数目的计算了,是s - (d[i] + 1) * c[ i ]

是的,我们正常只能对第i个组合到价值d[i] * c[i],但是这里是dp,接下来仍可能接着有c[i]。

所以我们计算不合理的,从不合理的开始 开始计算。

也就是我们取d[ i ]+ 1开始,在dp中接下来会取该硬币若干或者不取,所以从这里开始,这个算1种,接下来仍要填满背包,所以剩下的硬币随便组合,我们算的就是剩下硬币的组合数 ------ dp[ s - (d[i] + 1) * c[ i ] ]。

代码:

cpp 复制代码
int c[5];
int d[5];
int s;
int getw(int aim)
{
	return c[aim] * (d[aim]+1);
}

void solve()
{
	for (int i = 1; i <= 4; i++)
	{
		cin >> c[i];
	}
	int n;
	cin >> n;
	vector<int>dp(100005);
	dp[0] = 1;
	for (int i = 1; i <= 4; i++)
	{
		for (int j = c[i]; j <= 100000; j++)
		{
			dp[j] += dp[j - c[i]];
		}
	}


	for (int i = 0; i < n; i++)
	{
		for (int j = 1; j <= 4; j++)
		{
			cin >> d[j];
		}
		cin >> s;
		int ans = dp[s];

		for (int i = 1; i < 16; i++)
		{
			int tmp = 0;
			int cnt = 0;//奇数减,偶数加,容斥
			if (i & 1)
			{
				tmp += getw(1); cnt++;
			}
			if (i & 2)
			{
				tmp += getw(2); cnt++;
			}
			if (i & 4)
			{
				tmp += getw(3); cnt++;
			}
			if (i & 8)
			{
				tmp += getw(4); cnt++;
			}
			if (tmp > s)continue;
			
			if (cnt % 2 == 0)
				ans += dp[s - tmp];
			else
				ans -= dp[s - tmp];
		}
		cout << ans << endl;
	}

}
signed main()
{
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int t = 1;
	//cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}
相关推荐
我不是程序猿儿14 小时前
【C#】WinForms 控件句柄与 UI 刷新时机
开发语言·ui·c#
十五年专注C++开发14 小时前
Qt-Nice-Frameless-Window: 一个跨平台无边框窗口(Frameless Window)解决方案
开发语言·c++·qt
凯歌的博客15 小时前
python虚拟环境应用
linux·开发语言·python
祈祷苍天赐我java之术15 小时前
如何在Java中整合Redis?
java·开发语言·redis
学习路上_write16 小时前
STM32回调函数使用/定时器/GPIO/串口/
c语言·单片机·嵌入式硬件
froginwe1116 小时前
HTML5 测验
开发语言
czy878747517 小时前
C语言实现状态模式
c语言·状态模式
czy878747517 小时前
C语言实现迭代器模式
c语言·迭代器模式
野生技术架构师17 小时前
牛客网Java 高频面试题总结(2025最新版)
java·开发语言·面试
一只鹿鹿鹿17 小时前
系统安全设计方案书(Word)
开发语言·人工智能·web安全·需求分析·软件系统