乱七八糟笔记

P1450 [HAOI2008] 硬币购物

题目描述

共有 4 种硬币。面值分别为 c1,c2,c3,c4

某人去商店买东西,去了 n 次,对于每次购买,他带了 dii 种硬币,想购买 s 的价值的东西。请问每次有多少种付款方法。

输入格式

输入的第一行是五个整数,分别代表 c1,c2,c3,c4,n

接下来 n 行,每行有五个整数,描述一次购买,分别代表 d1,d2,d3,d4,s

输出格式

对于每次购买,输出一行一个整数代表答案。

数据规模与约定

  • 对于 100% 的数据,保证 1ci,di,s1051n1000

思路

1st.转化题面

求方程 c1X1+c2X2+c3X3+c4X4=s 的解的个数。
其中0Xidi

2nd.猜测算法

  • 一.多重背包
    考虑有解的重复性问题,以及数据量过大。
    否决。
  • 二.完全背包加容斥原理
    考虑用完全背包算出所有解的数量,再用容斥原理消去错解数量。
    通过。

3rd.求错解

简化方程,其中 Cn 为余项, Cn=ac1+bc2+cc3+dc4
s=Xc1+Cn
X=di+1 时,则 (X+a),b,c,d 必定是一组错解,因为不论 a 的取值,必有(X+a)>d1
接下来只须枚举 i ,用完全背包计算 s(di+1)ci 的解的个数,再用总解数减去。
但这样的话可能有重复解,用容斥原理消去即可。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N = 1e5;
int c[10], d[10], n, s;
int f[100010], ans;

void dfs(int dep, int tmp, int num) {
	if (dep > 4) {
		if (!num || tmp < 0) return;
		ans += (num % 2) ? f[tmp] : f[tmp] * (-1);
		return;
	}
	dfs(dep + 1, tmp - c[dep] * (d[dep] + 1), num + 1);
	dfs(dep + 1, tmp, num);
}

signed main() {
	for (int i = 1; i <= 4; i++) cin >> c[i];
	cin >> n;
	f[0] = 1;
	for (int i = 1; i <= 4; i++)
		for (int j = c[i]; j <= N; j++)
			f[j] += f[j - c[i]];
	while(n--) {
		for (int i = 1; i <= 4; i++) cin >> d[i];
		cin >> s;
		ans = 0;
		dfs(1, s, 0);
		cout << f[s] - ans << '\n';
	}
    return 0;
}

同理题目:P3951 [NOIP 2017 提高组] 小凯的疑惑

本文作者:CJY_QAQ

本文链接:https://www.cnblogs.com/cjyqaq/p/18740834

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   CJY_QAQ  阅读(3)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.