动态规划专题

其实已经做了不少题了,开个坑记一下在之前培训中遗留下来的题

CF327E 状压dp水题。一个小trick,如何比线性快的获取\(S\)的每位二进制?
for(int i = S;i;i -= lowbit(i))dp[S] += dp[S & ~lowbit(i)]要比每位分别判断要快

BZOJ4057 对于S中每位1,可以先预处理一下再枚举(注意这种情况是要在复杂度大于线性的时候用,否则就失去意义了,预处理跑的比算法还慢)

CF1101D 遇见gcd/lcm 考虑质因数

CF1039D 根号分治,显然当\(k \geq \sqrt{n}\)的时候答案最大是\(\sqrt{n}\),因此不同的答案数是\(O(\sqrt{n})\)级别的。对\(k\)较大的部分使用二分。考虑对于某个给定的k如何计算。设\(dp[i]\)表示以 i 为根节点的子树的答案,转移贪心即可。时限 7s 依旧是个卡常的辣鸡题。树形dp时可以用逆dfs序模拟递归过程,记录一下父亲并转移即可。时间复杂度\(O(nlogn\sqrt{n})\)最大点只需要跑1.2s

Luogu4161 / 6280 见题解

Luogu1365 设\(dp[i]\)表示考虑到位置 i 的期望。考虑combo,如果是 o 则combo+1,x则combo=0,? combo有一般概率 +1 一半概率 = 0,因此= (.+1)/2

Luogu1006 \(dp[i][j][k][l]\)表示传到(i,j),(k,l)的最大值,转移显然

Luogu1850 \(dp[i][j][0/1]\)表示当前在第 i 时间段,加上本次一共用了 j 次机会,当前申请 / 没有申请的最小期望路程。转移分情况讨论,例如:\(dp[i][j][1] = dp[i-1][j-1][1] + (k[i-1]) * (k[i]) * dis[d[i-1]][d[i]] + (k[i-1])*(1-k[i]) * dis[d[i-1]][c[i]] + (1-k[i-1]) * k[i] * dis[c[i-1]][d[i]] + (1-k[i-1]) * (1-k[i]) * dis[c[i-1]][c[i]]\),其余转移同理

Luogu4322 浮点二分答案之后转化为经典的(有总元素个数限制的)树形背包,直接写复杂度是\(O(nK^2)\)的,但是如果我们将K和size取个min,就可以做到\(O(nk)\),直接dfs会被卡常

CF1097G 利用斯特林数降幂之后变成一个\(C(f(X),i)\)对X求和的形式,考虑其组合意义,类似于一个树形背包。细节略多,感觉没有完全理解

CF1061C \(dp[i][j]\)表示原数列到位置 i,子序列到 j的方案数,转移对\(a[i]\)的因子枚举即可。注意需要滚动数组,而常规写法\(dp[i&1][j]\)会超时,只能改成\(dp[j]\)一类的,注意转移顺序!

CF886E 设\(f[i]\)表示考虑1~i的排列,其中能使程序运行到结尾的方案数。显然运行到结尾的一个必要条件就是i位于\([i-k+1,i]\),考虑枚举i的位置转移。\(f[i] = \sum_{j=i-k+1}^{i}f[j-1]*C_{i-1}^{i-j}*(i-j)!\),化简可得\(f[i] = (i-1)!\sum_{j=i-k+1}^{i}\frac{f[j-1]}{(j-1)!}\),后面的和式显然可以用前缀和维护。考虑统计答案,先考虑结果正确的方案数,即枚举n的位置,是\(\sum_{i=1}^nf[i-1]*C_{n-1}^{n-i}*(n-i)!\),用n!减去即可。
注意这种只关注相对大小的题,可以考虑用一个相对大小相同的排列代替,然后乘以一个组合数即可

CF1096D 设\(dp[i][0/1/2/3]\)表示考虑到第i个位置,"hard"没有出现/出现了h/ha/har的最小代价

CF1043F 观察到一个关键性质:如果有解,答案一定不会超过7(每次有一个新元素加进来之后gcd一定会除以一个质因子,否则gcd不变,这个数删去答案更优,这里不考虑gcd=2^2, 2^3.. 的情况是因为取一个质因数次数更小的数,答案一定不会变差,而2*3*5*7*11*13*17>3e5),枚举答案长度len,设\(dp[i]\)表示当前len,集合gcd为i的方案数。设\(cnt[i]\)表示a中有多少数能被i整除,显然可以预处理得到。那么转移就是\(dp[i] = C(cnt[i],len) - dp[j], i|j且j>i\),最后判断一下dp[1]是否不为0即可。注意这个题不是对答案进行dp,而是用dp判断类似可能性一类的问题

Luogu1450 如果没有限制,就是一个完全背包了;如果有一个钱的限制,答案就是\(dp[S] - dp[S - C[i] * (D[i]+1)]\),原因是考虑钦定拿出D[i]+1个C[i],然后剩下的随便选。如果有2,3,4个也一样,容斥一下即可

Luogu2627 单调队列优化dp。设\(dp[i]\)表示考虑到第 i 个且钦定 i 不选的答案,式子写出来之后单调队列维护\(dp[j]-sum[j]\)即可。注意2个细节:\(i\leq k+1\)的时候需要额外初始化;以及最后需要额外计算n也选了的情况

51nod1636 / CF119C
首先按照难度排序,注意到 \(b_i - a_i\) 很小,以此设计状态:设 \(dp[i][lst][delta]\) 表示当前第 \(i\) 天,上一天选了第 \(lst\) 们课,delta就是 \(lst.a\) + delta 表示今天的作业量,转移枚举一下下一天上哪个课,注意判断一下状态是否合法!!

CF533B
\(dp[x][0/1]\) 表示 \(x\)\(x\) 的子树中有 偶数/奇数 个在集合中的最大权值
然后考虑转移:\(dp[x][0] = max(dp[x][0]+dp[u][0], dp[x][1]+dp[u][1])\)\(dp[x][1] = max(dp[x][1]+dp[u][0], dp[x][0]+dp[u][1])\),(为什么要记录奇数的情况?有可能是多个奇数组合形成的下属个数为偶数),然后统计完子树答案之后考虑 \(x\) 这个点。前面 dp 值是没考虑 \(x\) 的结果,显然如果 \(dp[x][0]\) 的情况下,\(x\) 就可以选,也就是 \(dp[x][1] = max(dp[x][1], dp[x][0] + a[x])\) ,这样也保证了 \(x\) 的状态是合法的(如果x的子树选了奇数个,那么x一定不选,否则x可能选),数学归纳法得到所有的dp值都是合法的。最后答案就是 \(max(dp[1][1],dp[1][0])\),注意 \(dp[x][1]=-inf\) 初始化,因为转移的时候认为 dp[x][0/1] 表示的是不含 x 的子树的情况,而开始时相当于空树,含奇数的情况不存在

posted @ 2022-09-13 18:44  SkyRainWind  阅读(34)  评论(0编辑  收藏  举报