首页 > 其他分享 >AT_abc169_f Knapsack for All Subsets题解

AT_abc169_f Knapsack for All Subsets题解

时间:2024-03-02 22:00:25浏览次数:28  
标签:选择 Subsets int 题解 ll abc169 子集 dp mod

如果我们定义\(dp[i][j]\)表示对于前i个字符而言,其子集满足条件的个数。那4么对于一个位置i而言,要么选择它贡献要么不选择,所以

\(dp[i][j] = dp[i - 1][j - a[i]](j >= a[i]) + dp[i - 1][j]\),这是每一个\(f(i)\)的函数。

然后我们加上所有的\(dp[i][k](i : 1 到 n)ans += dp[i][k]\)

似乎\(ans\)就是答案。但是这样显然是有问题的。因为我们求的\(S\)的子集,而这里我们只求了\(S\)所有的前缀的\(f\)函数之和。

那么我们考虑对于一个\(S\)的子集,它的大小是\(siz\),而且满足其中元素的和是\(k\),那么它对全局\(S\)的贡献是\(2^{n-siz}\),因为如果这个子集的贡献增加1,就代表必须选完这\(siz\)个元素,其它的选择或者不选择。这样将元素加起来就会构成一个新的集合,这个方案数就是\(2^{n - siz}\)。

但是如何运用\(dp\)进行计算呢?这里我有一个固定的思维,就是我给了\(i\)两个限制,一个是子集的子集上的,一个是子集上的。意思是说,\(T\)是\(S\)的子集,\(X\)是\(T\)的子集,我找到了满足条件的\(X\),其中\(X\)是从前\(i\)个字符中选择的。在我的上一个\(dp\)中,这样的\(X\)的贡献只会给连续的前\(i\)个的S的子集T。

Ca都觉得自己没说的很清楚。总而言之就是,我们i的限制仅仅只是对于前i个子集而言的,我们的贡献是在全局上的。\(dp[i][j]\)表示选择\(X\)子集,\(X\)在前\(i\)中选择,对于所有的\(X\)而言,对所有的\(T\)的贡献的总和。也就是在前\(i\)个元素中选择子集,全局中所有\(f(T)\)(含有子集价值之和为j)之和的答案。

初始化是\(dp[0][0] = 2 ^ n\), 全局\(2 ^ n\)个子集都是含有空集,但是显然我们在后面选的时候是不能为空集的,这里也提示了为什么/2

\(dp[i][j] = dp[i - 1][j] + dp[i - 1][j - a[i]] /div 2\)

首先要加上我们之前已经算好了可以贡献j个的,然后我们在i - 1个元素之前计算\(f(j - a[i])\)的时候,既然已经减少了,就代表这个元素一定是要选择的,那么我们在计算\(f(j - a[i])\)的时候,对i这个位置肯定是没有任何限制的,但是我们现在必须选,所以对全局的贡献就会在之前的基础上少一半,少的是我满足和是\(j - a[i]\)但是我没有选择\(a[i]\)的方案。

到了这里ca就有一种感觉,\(dp[0][0]\)表示我最开始所有的方案数都是满足条件的,但是我在对和有了要求,于是这个位置就会产生选择或者不选则的要求,于是我们的答案就会有\(\div 2\)的变化。

神奇体验。Qwq

  • 菜就多练。
#include <bits/stdc++.h>
using namespace std;
const int N = 3005;
typedef long long ll;
const int mod = 998244353;
int dp[N][N], n, k, a[N], ans = 0, yyz; 
int q_pow(int a, int b)
{
	int res = 1;
	while(b)
	{
		if(b & 1) res = (ll)res * a % mod;
		a = (ll)a * a % mod;
		b >>= 1;
	}
	return res;
}
int main()
{
	scanf("%d %d", &n, &k);
	for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
	dp[0][0] = q_pow(2, n);
	yyz = q_pow(2, mod - 2);
	for (int i = 1; i <= n; ++ i)
	{
		for (int j = 0; j <= k; ++ j) 
		{
			if(j >= a[i]) dp[i][j] = (ll)dp[i - 1][j - a[i]] * yyz % mod;
			dp[i][j] = (ll)(dp[i][j] + dp[i - 1][j]) % mod;
		}
	}
	printf("%lld", (ll)(dp[n][k] + mod) % mod);//好习惯 
} 

标签:选择,Subsets,int,题解,ll,abc169,子集,dp,mod
From: https://www.cnblogs.com/ybC202444/p/18049320

相关文章

  • CF1383A String Transformation 1 题解
    若某一位\(i\)上\(A_i>B_i\),则显然无解。否则,建立并查集,然后遍历字符串,若\(A_i,B_i\)不在一个集合就合并\(A_i\)与\(B_i\),直到只剩下一个集合,此时的合并总次数即为答案。为什么呢?因为将\(A_i,B_i\)合并的操作可以视为等价于将以\(A_i\)开头的连续若干个相同字符均改......
  • 「TFOI R1」Unknown Graph 题解
    这里是出题人题解。\(\text{SolutionOfProblemC:UnknownGraph.}\)题意还是很清晰的,这里就不再赘述题意了。首先如果没有\(q\)的限制,显然有一种贪心思想就是每个点每次选剩余入度最多的与之连边。但是因为限制,就无法保证贪心的正确性。那该怎么办呢?一个大提示:这题是......
  • P3200 [HNOI2009] 有趣的数列 题解
    P3200[HNOI2009]有趣的数列感性地,我们认为在按照数值从小到大填数时每个时刻所填的奇数位的个数\(x\)不小于所填偶数位的个数\(y\)。我们考虑如何证明这一点。性质1:每一个偶数位上的数都要大于它前面所有的数。这一点应当是显然的。性质2:每一个偶数位上的数都不小于它的下......
  • AT_nikkei2019_2_qual_d Shortest Path on a Line 题解
    我们发现,brute-force的复杂度的优化瓶颈主要在建图上。于是我们有一个巧妙的转化:因为所有满足\(L\leS,T\leR\)的所有边\((S,T)\)的长度均为\(C\)。然后题目要求的是\(1\simN\)的最短路。那么在边权相等的情况下,走到的点的编号一定越大越好。于是在所有点对\((......
  • AT_abc243_e [ABC243E] Edge Deletion 题解
    首先,我们可以得出一个结论:令点\(i,j\)之间的最短路径边权和\(dis_{i,j}\),若存在一个点\(k\),使得\(k\neqi\)且\(k\neqj\)且\(dis_{i,k}+dis_{k,j}=dis_{i,j}\),则连接\(i,j\)的边可以被删去。该结论的正确性是显然的,因为将连接\(i,j\)的边删去后,\(i,j\)之间的......
  • AT_arc083_b [ABC074D] Restoring Road Network 题解
    难度虚高,建议评橙/黄qwq。首先我们发现这是一道最短路问题,且\(N\le300\),于是采取floyd算法解决。具体地,我们分情况分类讨论。令我们当前枚举到的最短路径起点为\(i\),终点为\(j\),中转点为\(k\),输入的矩阵为\(dis\)。若\(dis_{i,j}>dis_{i,k}+dis_{k,j}\),则一定无......
  • P9184 [USACO23OPEN] Moo Language B 题解
    恶♂趣♂味♂大♂模♂拟♂。首先是构造语句部分:开始肯定是尽可能地多用上不及物语句和及物语句;接着,因为及物语句的单词数量一定比不及物语句多,所以贪心地尽可能多地将不及物语句改为及物语句;然后,为了增加语句长度,再次贪心地在及物语句中尽可能多地添加名词和逗号即可。......
  • CF1856E1 PermuTree (easy version) 题解
    假定当前在节点\(u\),它拥有两棵子树\(v,w\),此时\(u\)是\(\operatorname{lca}(v,w)\)。我们一定可以构造出一个排列\(a\),使得所有满足\(i\inv\)的节点\(i\)和满足\(j\inw\)的节点\(j\),有\(a_i<a_u<a_j\)。因此此时点\(u\)对于答案的贡献即为\(size_v\times......
  • P9183 [USACO23OPEN] FEB B 题解
    由于只需要考虑相邻的位置,所以每一段连续的F是互不影响的,可以分别进行考虑。而连续的一段F又可以分成两类:靠边的和被夹在中间的。靠边的F段较为简单,假定有\(c\)个F,不难发现只要让EB交错出现就可以达到最少次数,而让所有的F都变成最近的非F就可以达到最多次数\(c......
  • P3671 [USACO17OPEN] Where's Bessie? S 题解
    我们先枚举所有子矩阵,验证其在不考虑重叠的情况下是否为PCL矩阵(dfs求一遍联通块即可)。然后将所有满足条件的矩阵存下来,最后朴素判断每个矩阵是否被其他矩阵包括,若没有矩阵包括它,则其对于答案的贡献为\(1\),累加所有贡献即为最终结果。时间复杂度是\(O(n^6)\)的。思路很简......