首页 > 其他分享 >Coin Troubles题解(dp,拓扑序)

Coin Troubles题解(dp,拓扑序)

时间:2024-08-14 20:51:41浏览次数:12  
标签:限制 硬币 int 题解 Troubles fa Coin dp

Coin Troubles题解(dp,拓扑序)

题目链接:https://codeforces.com/problemset/problem/283/C

题意:

有\(n\)种硬币, 每种硬币都有一个价格\(ai\),现在有\(q\)个限制,每个限制会告诉你\((b,c)\),并要求\(b\)种硬币的数量严格大于\(c\)种硬币的数量。现在问你一共有多少种买硬币的方法,使得最后买硬币一共要\(t\)元。答案最后要求对\(10^9+7\)取模

思路:

对于每一个限制,我们首先想到,如果对于一个数,它限制的数如果限制了它本身,那么肯定一种方法都没有。刨去这种特殊情况,如果将每一种限制画出来连在一起(未限制和被限制的点单独出现),直观的看就是多个有向无环图,容易想到拓扑序,也就可以看成多个树和多个点。考虑每条链的最小贡献,对于每一个被限制的点,我们每次可以将它的所有父亲节点的值从t中减去,这样子就可以满足被限制的点的数量严格小于限制它的点的数量。

对于每一条链,我们可以把它作为一个整体考虑贡献,这样子我们就可以把这道题转化为完全背包dp了

代码如下:
#include<bits/stdc++.h>
using namespace std;
#define int long long // 不开long long见祖宗

const int N = 1e5 + 10, M = 310, mod = 1e9 + 7;
int k[M * 4], f[M][N], s[M], p[N], dp[N], fa[M];
int n, q, t;
vector <int> nxt[M];
int find(int x)
{
	if(p[x] == 0) return s[x];
	int fa = find(p[x]);
	return fa + s[x];
}
int find2(int x) // 找父亲
{
	return fa[x] == x ? x : fa[x] = find2(fa[x]);
}

signed main()
{
	int op = 0;
	cin >> n >> q >> t;
	for(int i = 1; i <= n; i++) cin >> s[i];
	for(int i = 1; i <= n; i++) fa[i] = i; // 预处理
	for(int i = 1; i <= q; i++)
	{
		int a, b;
		cin >> a >> b;
		if(find2(a) == find2(b)) // 找到环了
		{
			cout << '0';
			return 0;
		}
		fa[find2(a)] = find2(b);
		p[b] = a;
	}
	for(int i = 1; i <= n; i++)
	{
		if(p[i]) 
		{
			k[++op] = find(i);
			t -= (k[op] - s[i]);
		}
		else k[++op] = s[i];
	}
	if(t < 0) // 需要的硬币比拥有的硬币多,直接cout 0
	{
		cout << '0';
		return 0;
	}
	dp[0] = 1;
	for(int i = 1; i <= op; i++) // 完全背包
	{
		for(int l = 0; l + k[i] <= t; l++)
		{
			dp[l + k[i]] = (dp[l + k[i]] + dp[l]) % mod;
		}
	}
	cout << dp[t] % mod;
}

(本蒟蒻的第一篇题解,如有错误多多指正)

标签:限制,硬币,int,题解,Troubles,fa,Coin,dp
From: https://www.cnblogs.com/turt1e/p/18359733

相关文章

  • 【题解】CF - 859C : Pie Rules
    原题传送门题目大意:给定一个长为\(N(1\leqN\leq50)\)的序列,Bob和Alice轮流从序列的最前端进行以下操作之一:取出序列最前端的数,并将其加到自己的分数中;取出序列最前端的数,将其加到对方的分数中,则下一轮可继续操作。两人轮流操作直到序列被取完,分数多的一方获胜。若......
  • 暑期模拟赛题解
    暑期模拟赛题解CSP-J模拟赛2024.7.5CSP-J模拟赛1T1简单二分,判断即可。T2\(60pts\)的状压是好写的。至于\(100pts\),考虑dp状态的合并,由于\(m\)的级别很小,考虑对后\(m\)个数状压,考察满足条件的情况。dp难以优化的时候考察本质相同的状态。T3数据范围显......
  • 【题解】【模拟】——帮贡排序
    【题解】【模拟】——帮贡排序帮贡排序题目背景题目描述输入格式输出格式输入输出样例输入#1输出#1提示1.题意解析1.1.结构体储存信息1.2.输入后调整职务的排序规则1.3.分配职务的方法1.4.职务的映射1.5.输出时的排序规则1.6.主函数2.代码帮贡排序题目背景在......
  • 洛谷P2789 直线交点数 题解
    解题思路考虑将直线分组,每组内直线互相平行,任意两组直线间交点数量等于两组内直线数量乘积。分组操作使用dfs,求出交点数量后加入set去重,输出set大小。时间复杂度O(2NN2)有点鬼畜但是可以通过。实现#include<cstdio>#include<unordered_set>inta[30];std::unordered_set......
  • 题解:CF1551D1 Domino (easy version)
    题解:CF1551D1Domino(easyversion)分析题目中保证\(n\timesm\)为偶数,下面进行分类讨论。情况一如果\(n\)和\(m\)都是偶数,那么可以分割成\(\frac{n}{2}\times\frac{m}{2}\)个\(2\times2\)的方块。根据上图我们发现,只要\(k\)满足\(0\lek\le\frac{n}{2}\time......
  • 题解:CF685A Robbers' watch
    题解:CF685ARobbers'watch感觉这题难点主要在理解题意。题意一天\(n\)个小时,一小时\(m\)分钟,手表用\(7\)进制表示时间(位数未填满补前导零),求问这个手表显示的每一位数字都不一样的时刻数量。分析因为是\(7\)进制,所以每一个数字位只可能出现\(0\sim6\)这\(7\)种......
  • P8776 最长不下降子序列 题解
    Statement最长不下降子序列(LIS),但是有一次机会,让序列中连续\(k\)个数改成同一个数。\(n\le10^5,a_i\le10^6\).Solution记\(f(i)\)为以\(i\)结尾的LIS长度,\(g(i)\)为以\(i\)开始的LIS长度,可预处理.答案一定是\(f(i)+k+g(j)\)这样拼接起来的,其中\(i+k+1\le......
  • (CF 10D)最长公共上升子序列(LCIS)(要求输出序列) - 题解
    最长公共上升子序列(LCIS)原题链接:CodeForces、洛谷时间限制:C/C++1000MS,其他语言2000MS内存限制:C/C++256MB,其他语言512MB描述给定两个整数序列,写一个程序求它们的最长上升公共子序列。当以下条件满足的时候,我们将长度\(N\)的序列\(S_1,S_2,...,S_N\)称为长度为\(M......
  • 【题解】CF1942C1 Bessie's Birthday Cake (Easy Version)
    \(\mathfrak{1st.\Preamble\|}\)前言题目传送门:CF1942C1Bessie'sBirthdayCake(EasyVersion)。蒟蒻在洛谷上第一篇通过的题解。\(\mathfrak{2nd.\Reasoning\|}\)思路其实只需要把选中的点组成一个新的多边形,然后我们就可以发现有\(x\)个点的多边形可以连出\(x-2......
  • 【知识】并查集的单点删除 &【题解】SP5150
    \(\mathfrak{1st.}\)前言-->题目传送门<--原先这道题的难度是紫,我觉得题目翻译看不懂,就去讨论版发了个贴,然后题管更新了题目翻译,并且把难度降到了蓝……\(\mathfrak{2nd.}\)思路赶时间或嫌啰嗦的可以直接跳到『思路归纳』。我们先从普通并查集开始思考对于删除单点\(x\),......