CodeForces 283C Coin Troubles 分析+背包思想

很灵活的题目,题意简单,看到又是钱币问题,类似于那种给了一定数目T,有n种钱币,每种的价值,让你组合成总价值为T的方案数,但是加了一些限制条件,那就是某些种类钱币数量必须大于另一些种类的,加了个限制条件 我就脑残了,唉智商看来是真不够啊 ,后来看了别人的分析

倘若种类a的钱币数量必须要大于种类b的数量,那么如果我要 去 m张b种类的钱币,其实同时也是相当于已经取了m张a种类的,因为a必须大于b的嘛,所以我们可以通过这样来修改题目给的钱币的价值,若a种类数量必须大于b种类数量,且a种类价值为A,b种类为B,那么可以把 b种类的钱币修改为  A + B,同时要凑成的总价值T要先减去  !!!一个!!!a种类钱币的价值,这样后面随便怎么取都能满足 所取的方案  a种类数量大于b种类数量

这样就可以进行仿造背包的思想来进行递推求解了

恍然大悟去敲了

但是WA了很久,后来真是是已经WA了无数把了,没办法 看了别人的代码,发现 前面多了一些处理的东西,原来题目给的限制条件 比如有 a种类必须大于b种类,同时b要大于c,但是又有可能会出现c会大于a的,  这样就有环了,题目 所说的 给了q组限制条件,每组包含bi,ci  它说bi中不会重复出现相同的数,ci中也不会,但是bi 与cj还是有可能相同的,所以会有  环的情况出现,还是读题不够仔细啊 ,题目不错的,分析过程揭开以后觉得不难,但是下手 感觉没法出手,是个好题目

http://codeforces.com/contest/283/problem/C

#include<iostream>
#include<cstdio>
#include<list>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<cmath>
#include<memory.h>
#include<set>

#define ll long long

#define eps 1e-8

const int inf = 0xfffffff;

const ll INF = 1ll<<61;

using namespace std;

//vector<pair<int,int> > G;
//typedef pair<int,int > P;
//vector<pair<int,int> > ::iterator iter;
//
//map<ll,int >mp;
//map<ll,int >::iterator p;

#define MOD 1000000007 

int nn[355];

int b[355];
int c[355];
int father[355];
int in[355];
ll dp[1000000 + 5];
bool flag;

void init() {
	memset(nn,0,sizeof(nn));
	memset(b,0,sizeof(b));
	memset(c,0,sizeof(c));
	memset(in,0,sizeof(in));
	memset(father,0,sizeof(father));
	memset(dp,0ll,sizeof(dp));
	flag = false;
}

void input(int &n,int &q,int &t) {
	scanf("%d %d %d",&n,&q,&t);
	for(int i=1;i<=n;i++)
		scanf("%d",&nn[i]);
	for(int i=0;i<q;i++) {
		scanf("%d %d",&b[i],&c[i]);
		father[b[i]] = c[i];
		in[c[i]]++;

	}
}

void cal(int &n,int &q,int &t) {
	for(int i=0;i<q;i++) {
		int tmp = 0;
		for(int j=1;j<=n;j++) {
			if(father[j] && in[j] == 0) {
				tmp = j;break;
			}
		}
		if(!tmp) {puts("0");flag = true;return ;}
		int pre = father[tmp];
		in[pre]--;
		father[tmp] = 0;
		t -= nn[tmp];
		nn[pre] += nn[tmp];
		if(t < 0) {puts("0");flag = true;return ;}
	}
}

void DP(int &n,int &t) {
		dp[0] = 1;//都不取
	for(int i=1;i<=n;i++) {
		if(nn[i] > t)continue;
		for(int j=0;j + nn[i] <= t;j++)
			dp[j + nn[i]] = (dp[j + nn[i]] + dp[j])%MOD;
	}
}

void output(int &t) {
	printf("%I64d\n",dp[t]);
}

int main() {
	int n,q,t;
	init();
	input(n,q,t);
	cal(n,q,t);
	if(flag)return 0;
	DP(n,t);
	output(t);
	return 0;
}

CodeForces 283C Coin Troubles 分析+背包思想

时间: 2024-10-25 13:11:31

CodeForces 283C Coin Troubles 分析+背包思想的相关文章

codeforces 148E Aragorn&#39;s Story 背包DP

Aragorn's Story Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/148/E Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who

uva674 - Coin Change(完全背包)

题目:uva674 - Coin Change(完全背包) 题目大意:给1 5 10 25 50 这5中面值的硬币,然后给出N,问用这些钱组成N的不同方式数目.1 5 和 5 1 表示同一中,顺序不同算相同. 解题思路:完全背包. 状态方程:dp[j] += dp[ j - v[i]]: 代码: #include <cstdio> #include <cstring> const int N = 5; const int maxn = 8000; typedef long long

01背包思想解决组合问题并输出组合

//01背包思想 每个数都有 选 与 不选 两种可能 #include<cstdio>int n, r;bool Vis[21] = {false}; void DFS(int index, int nowR){        //边界    if(index == n+1){            // 说明已经遍历完了 n个数        if(nowR == r) {          //说明刚好选了r个数             for(int i = 1; i <= n;

C. Coin Troubles 有依赖的背包 + 完全背包变形

http://codeforces.com/problemset/problem/283/C 一开始的时候,看着样例不懂,为什么5 * a1 + a3不行呢?也是17啊 原来是,题目要求硬币数目a3 > a4 > a2,那么,不选的话,是不合法的.就是0.0.0这样是不合法的,因为a3 = a4了. 那么就可以知道, a3起码都要选两个了. 那么怎么维护这个关系呢?,思路是有依赖的背包,需要a3的数目比a4的多,就可以把a4那件物品变成a3 + a4 那么每一次选择的时候,就隐含地选了一件a3

LightOJ 1231 Coin Change (I) (背包计数模板题)

1231 - Coin Change (I) PDF (English) Statistics Forum Time Limit: 1 second(s) Memory Limit: 32 MB In a strange shop there are n types of coins of valueA1, A2 ... An.C1, C2,... Cn denote the number of coins of valueA1, A2... An respectively. You have

POJ 1947 Rebuilding Roads (树dp + 背包思想)

题目链接:http://poj.org/problem?id=1947 一共有n个节点,要求减去最少的边,行号剩下p个节点.问你去掉的最少边数. dp[u][j]表示u为子树根,且得到j个节点最少减去的边数. 考虑两种情况,去掉孩子节点v与去不掉. (1)去掉孩子节点:dp[u][j] = dp[u][j] + 1 (2)不去掉孩子节点:dp[u][j] = min(dp[u][j - k] + dp[v][k]) 综上就是dp[u][j] = min(dp[u][j] + 1, min(dp[

『嗨威说』算法设计与分析 - 动态规划思想小结(HDU 4283 You Are the One)

本文索引目录: 一.动态规划的基本思想 二.数字三角形.最大子段和(PTA)递归方程 三.一道区间动态规划题点拨升华动态规划思想 四.结对编程情况 一.动态规划的基本思想: 1.1 基本概念: 动态规划算法简单说,利用拆解问题思想,定义问题状态和状态之间的关系,使得问题能够以递推或者是分治的方式去解决. 动态规划算法的基本思想与分治法很相似,将待求解的问题分解为若干个子问题,前一子问题的解,为后一子问题的求解所依赖.在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解

Codeforces 837D Round Subset(背包)

题目链接  Round Subset 题意  在n个数中选择k个数,求这k个数乘积末尾0个数的最大值. 首先我们预处理出每个数5的因子个数c[i]和2的因子个数d[i] 然后就可以背包了. 设f[i][j]为选i个数,5的因子总和为j时,2的因子总和的最大值. 则状态转移方程为 $f[i][j] = max(f[i - 1][j - c[k]] + d[k])$ 注意边界条件 时间复杂度$O(5200nk)$ #include <bits/stdc++.h> using namespace s

codeforces:818G Four Melodies分析

题目 题目大意是有一组自然数v1,...,vn,要求在其中找到四个非空子序列(从原来的自然数序列中挑选一部分数,并按原先后关系排序),这些子序列互不相交,且每个子序列中的前后元素的值要么差值的绝对值为1,要么对7取余的值相同. 输入自然数序列的长度n满足4<=n<=3000,而每个输入的自然数均不超过1e5. 求解所有满足以上条件的这样四个子序列的长度的总和的最大可能值.  预处理 这道题有点难度,考察的知识范围很大.我个人也是参考了codeforces上的tutorial.要解决这个问题必须