动态规划之i次方

前言

收录了一些比较秀的题目。
此博客待更新。

一些好的题目

T1 GDOI2018 T6 滑稽子图

考虑 O ( n 2 ) O(n^2) O(n2)的转移。
f [ x ] [ i ] [ 0 / 1 ] f[x][i][0/1] f[x][i][0/1]表示 x x x的子树,选了i条边,x是否被选。
则有如下的转移:
f n e w [ x ] [ i ] [ 0 ] = ∑ j = 0 i f o l d [ x ] [ j ] [ 0 ] ∗ ( f o l d [ y ] [ i − j ] [ 0 ] + f o l d [ y ] [ i − j ] [ 1 ] ) f_{new}[x][i][0]=\sum_{j=0}^i f_{old}[x][j][0]*(f_{old}[y][i-j][0]+f_{old}[y][i-j][1]) fnew[x][i][0]=j=0ifold[x][j][0](fold[y][ij][0]+fold[y][ij][1])
f n e w [ x ] [ i ] [ 1 ] = ∑ j = 0 i f o l d [ x ] [ j ] [ 1 ] ∗ f o l d [ y ] [ i − j ] [ 0 ] f_{new}[x][i][1]=\sum_{j=0}^i f_{old}[x][j][1]*f_{old}[y][i-j][0] fnew[x][i][1]=j=0ifold[x][j][1]fold[y][ij][0]
f n e w [ x ] [ i ] [ 1 ] = ∑ j = 0 i − 1 f o l d [ x ] [ j ] [ 1 ] ∗ f o l d [ y ] [ i − 1 − j ] [ 1 ] f_{new}[x][i][1]=\sum_{j=0}^{i-1} f_{old}[x][j][1]*f_{old}[y][i-1-j][1] fnew[x][i][1]=j=0i1fold[x][j][1]fold[y][i1j][1]
答案即为 ∑ i = 1 n − 1 i k ∗ ( f [ 1 ] [ i ] [ 0 ] + f [ 1 ] [ i ] [ 1 ] ) \sum_{i=1}^{n-1}i^k*(f[1][i][0]+f[1][i][1]) i=1n1ik(f[1][i][0]+f[1][i][1])
其实这个转移跟k无关,可以用点分治+NTT优化。。。。
因为 k ≤ 10 k\leq 10 k10,所以考虑 O ( n k 2 ) O(nk^2) O(nk2)的转移。
直接考虑贡献。上面的三条转移式,对应着4条转移。
先考虑第一个(以 f [ x ] [ i ] [ 0 ] ∗ f [ y ] [ j ] [ 0 ] f[x][i][0]*f[y][j][0] f[x][i][0]f[y][j][0]为例),其余三个类似。
合并贡献, f [ x ] [ i ] [ 0 ] ∗ i k f[x][i][0]*i^k f[x][i][0]ik, f [ y ] [ j ] [ 0 ] ∗ j k f[y][j][0]*j^k f[y][j][0]jk变成 f [ x ] [ i ] [ 0 ] ∗ f [ y ] [ j ] [ 0 ] ∗ ( i + j ) k f[x][i][0]*f[y][j][0]*(i+j)^k f[x][i][0]f[y][j][0](i+j)k
= f [ x ] [ i ] [ 0 ] ∗ f [ y ] [ j ] [ 0 ] ∗ ( ∑ l = 0 k C k l ∗ i k ∗ j k − l ) =f[x][i][0]*f[y][j][0]*(\sum_{l=0}^kC_k^l*i^k*j^{k-l}) =f[x][i][0]f[y][j][0](l=0kCklikjkl)
= ∑ l = 0 k C k l ∗ f [ x ] [ i ] [ 0 ] ∗ f [ y ] [ j ] [ 0 ] ∗ i k ∗ j k − l =\sum_{l=0}^k C_k^l*f[x][i][0]*f[y][j][0]*i^k*j^{k-l} =l=0kCklf[x][i][0]f[y][j][0]ikjkl
= ∑ l = 0 k C k l ( ∑ i = 0 s i z [ x ] − 1 f [ x ] [ i ] [ 0 ] ∗ i k ) ∗ ( ∑ j = 0 s i z [ y ] − 1 f [ y ] [ j ] [ 0 ] ∗ j k − l ) =\sum_{l=0}^k C_k^l(\sum_{i=0}^{siz[x]-1}f[x][i][0]*i^k)*(\sum_{j=0}^{siz[y]-1}f[y][j][0]*j^{k-l}) =l=0kCkl(i=0siz[x]1f[x][i][0]ik)(j=0siz[y]1f[y][j][0]jkl)
g [ x ] [ l ] = ∑ i = 0 s i z [ x ] − 1 f [ x ] [ i ] [ 0 ] ∗ i l g[x][l]=\sum_{i=0}^{siz[x]-1}f[x][i][0]*i^l g[x][l]=i=0siz[x]1f[x][i][0]il
直接转移g即可。
g n e w [ x ] [ k ] = ∑ l = 0 k g o l d [ x ] [ l ] ∗ g [ y ] [ k − l ] ∗ C k l g_{new}[x][k]=\sum_{l=0}^k g_{old}[x][l]*g[y][k-l]*C_k^l gnew[x][k]=l=0kgold[x][l]g[y][kl]Ckl
答案即为 g [ 1 ] [ k ] g[1][k] g[1][k]

T2 JZOJ 4424 道路

有一个n个点的图,点两两之间可以连边。
假设连k条边使得这n个点两两之间有路径可达,这算是一种合法的方案。
这种方案对答案的贡献为 k 2 k^2 k2
求所有合法方案的和。
看一道与这题有关联的题。
JZOJ3303城市规划
这道题目要求n个点的简单(无重边无自环)无向连通图数目。
O ( n 2 ) O(n^2) O(n2)做法
f [ n ] f[n] f[n]表示n个点的答案, g [ n ] g[n] g[n]表示n个点的图的数目。
显然, g [ n ] = 2 C n 2 g[n]=2^{C_n^2} g[n]=2Cn2
考虑1号点所在连通块的大小。
f [ n ] = g [ n ] − ∑ i = 1 n − 1 f [ i ] ∗ g [ n − i ] ∗ C n − 1 i − 1 f[n]=g[n]-\sum_{i=1}^{n-1} f[i]*g[n-i]*C_{n-1}^{i-1} f[n]=g[n]i=1n1f[i]g[ni]Cn1i1
但是现在要求得是每种方案的平方的和。
在JZOJ4424种,设 f [ n ] [ 0 / 1 / 2 ] f[n][0/1/2] f[n][0/1/2]表示n个点,要求连通的方案的 0 / 1 / 2 0/1/2 0/1/2次方和。
g [ n ] [ 0 / 1 / 2 ] g[n][0/1/2] g[n][0/1/2]表示n个点,不要求连通的方案的 0 / 1 / 2 0/1/2 0/1/2次方和。
g [ n ] [ 0 ] = 2 C n 2 g[n][0]=2^{C_n^2} g[n][0]=2Cn2
g [ n ] [ 1 ] = C n 2 ∗ 2 C n 2 − 1 g[n][1]=C_n^2*2^{C_n^2-1} g[n][1]=Cn22Cn21
在每种方案中,每条边对 g [ n ] [ 2 ] g[n][2] g[n][2] 1 2 = 1 1^2=1 12=1的贡献,每对边(不相同)对 g [ n ] [ 2 ] g[n][2] g[n][2] 2 ∗ 1 ∗ 1 2*1*1 211的贡献。
g [ n ] [ 2 ] = g [ n ] [ 1 ] + ( C n 2 ) ∗ ( C n 2 − 1 ) ∗ ( 2 C n 2 − 2 ) g[n][2]=g[n][1]+(C_n^2)*(C_n^2-1)*(2^{C_n^2-2}) g[n][2]=g[n][1]+(Cn2)(Cn21)(2Cn22)
当然了, g [ n ] [ 2 ] g[n][2] g[n][2]还可以从 g [ n − 1 ] [ 2 ] g[n-1][2] g[n1][2]转移过来。考虑点与n-1个点中哪些点连边。
g [ n ] [ 2 ] = ∑ i = 0 n − 1 C n − 1 i ∗ ( i 2 + 2 ∗ i ∗ g [ n − 1 ] [ 1 ] + g [ n − 1 ] [ 2 ] ) g[n][2]=\sum_{i=0}^{n-1}C_{n-1}^i*(i^2+2*i*g[n-1][1]+g[n-1][2]) g[n][2]=i=0n1Cn1i(i2+2ig[n1][1]+g[n1][2])
考虑f的转移。算f的套路。
目标:减去很多个式子。方法:每个式子拆开算。即算式子的每一项,然后再加起来。
目前图中有一个大小为i的连通块,和剩余n-i个节点的不要求连通的图(设此图有j条边)。
现在要算 ( i + j ) 2 (i+j)^2 (i+j)2。则就要算 i 2 , 2 ∗ i ∗ j , j 2 i^2,2*i*j,j^2 i2,2ij,j2出现多少次。
i 2 i^2 i2出现了 g [ n − i ] [ 0 ] g[n-i][0] g[ni][0]次, j 2 j^2 j2出现了 f [ i ] [ 0 ] f[i][0] f[i][0]次,每个 2 ∗ i ∗ j 2*i*j 2ij出现了1次。
f [ n ] [ 0 ] = g [ n ] [ 0 ] − ∑ i = 1 n − 1 C n − 1 i − 1 ∗ g [ n − i ] [ 0 ] f[n][0]=g[n][0]-\sum_{i=1}^{n-1}C_{n-1}^{i-1}*g[n-i][0] f[n][0]=g[n][0]i=1n1Cn1i1g[ni][0]
分成两个不连通的块计算
f [ n ] [ 1 ] = g [ n ] [ 1 ] − ∑ i = 1 n − 1 C n − 1 i − 1 ∗ ( f [ i ] [ 0 ] ∗ g [ n − i ] [ 1 ] + f [ i ] [ 1 ] ∗ g [ n − i ] [ 0 ] ) f[n][1]=g[n][1]-\sum_{i=1}^{n-1}C_{n-1}^{i-1}*(f[i][0]*g[n-i][1]+f[i][1]*g[n-i][0]) f[n][1]=g[n][1]i=1n1Cn1i1(f[i][0]g[ni][1]+f[i][1]g[ni][0])
f [ n ] [ 2 ] = g [ n ] [ 2 ] − ∑ i = 1 n − 1 C n − 1 i − 1 ∗ ( f [ i ] [ 0 ] ∗ g [ n − i ] [ 2 ] + f [ i ] [ 2 ] ∗ g [ n − i ] [ 0 ] + 2 ∗ f [ i ] [ 1 ] ∗ g [ n − i ] [ 1 ] ) f[n][2]=g[n][2]-\sum_{i=1}^{n-1}C_{n-1}^{i-1}*(f[i][0]*g[n-i][2]+f[i][2]*g[n-i][0]+2*f[i][1]*g[n-i][1]) f[n][2]=g[n][2]i=1n1Cn1i1(f[i][0]g[ni][2]+f[i][2]g[ni][0]+2f[i][1]g[ni][1])

T3 JZOJ 5911

题目:请点这里
题解:i的贡献,分为i的子树内的,和i的子树外的。
其实式子时不难推的。
处理子树内:设 f [ x ] [ 1 ] f[x][1] f[x][1]表示期望的1次方和, f [ x ] [ 2 ] f[x][2] f[x][2]表示期望的2次方和。
树形依赖式背包那样转移即可。

void dg2(int x){
 int i;
 for(i=head[x];i;i=edge[i].next)
     if(fa[0][x]^edge[i].to){
      dg2(edge[i].to);
      f[2][x]=(f[2][x]+2*(edge[i].val*f[1][x]%mo)*f[1][edge[i].to]%mo)%mo;
      f[2][x]=(f[2][x]+f[2][edge[i].to]*edge[i].val%mo)%mo;
      f[1][x]=(f[1][x]+f[1][edge[i].to]*edge[i].val%mo)%mo;
  }
  f[2][x]=(f[2][x]+(c[x]*f[1][x])%mo*2%mo+(c[x]*c[x])%mo)%mo;
  f[1][x]=(f[1][x]+c[x])%mo;
}

处理子树外:对于每个x,维护一个x的儿子的前缀期望和后缀期望。

总结

总而言之,寻找能够计算的两"块",这两“块”对答案的贡献独立。
合并的时候其中一块看成是常数,另一块看成是未知数。
T2里的例子:
g [ n ] [ 2 ] = ∑ i = 0 n − 1 C n − 1 i ∗ ( i 2 + 2 ∗ i ∗ g [ n − 1 ] [ 1 ] + g [ n − 1 ] [ 2 ] ) g[n][2]=\sum_{i=0}^{n-1}C_{n-1}^i*(i^2+2*i*g[n-1][1]+g[n-1][2]) g[n][2]=i=0n1Cn1i(i2+2ig[n1][1]+g[n1][2])
有两个块,n号点第一个块,设一种方案中其他块的边的数量为x。
∑ x = g [ n − 1 ] [ 1 ] \sum x=g[n-1][1] x=g[n1][1] ∑ x 2 = g [ n − 1 ] [ 2 ] \sum x^2=g[n-1][2] x2=g[n1][2]

f [ n ] [ 2 ] = g [ n ] [ 2 ] − ∑ i = 1 n − 1 C n − 1 i − 1 ∗ ( f [ i ] [ 0 ] ∗ ( ∑ x 2 ) + f [ i ] [ 2 ] ∗ ( ∑ 1 ) + 2 ∗ f [ i ] [ 1 ] ∗ ( ∑ x ) ) f[n][2]=g[n][2]-\sum_{i=1}^{n-1}C_{n-1}^{i-1}*(f[i][0]*(\sum x^2)+f[i][2]*(\sum 1)+2*f[i][1]*(\sum x)) f[n][2]=g[n][2]i=1n1Cn1i1(f[i][0](x2)+f[i][2](1)+2f[i][1](x))
∑ 1 = g [ n − 1 ] [ 0 ] , ∑ x = g [ n − 1 ] [ 1 ] ∑ x 2 = g [ n − 1 ] [ 2 ] \sum 1=g[n-1][0],\sum x=g[n-1][1] \sum x^2=g[n-1][2] 1=g[n1][0],x=g[n1][1]x2=g[n1][2]
T3里的例子:
f [ x ] [ 2 ] = f [ x ] [ 2 ] + 2 p ∗ f [ x ] [ 1 ] ∗ ( ∑ y ) + p ∗ ( ∑ y 2 ) ∗ f[x][2]=f[x][2]+2p*f[x][1]*(\sum y)+p*(\sum y^2)* f[x][2]=f[x][2]+2pf[x][1](y)+p(y2)
其中, ∑ y = f [ s o n [ x ] ] [ 1 ] \sum y=f[son[x]][1] y=f[son[x]][1] ∑ y 2 = f [ s o n [ x ] ] [ 2 ] \sum y^2=f[son[x]][2] y2=f[son[x]][2]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值