CF1204E Natasha, Sasha and the Prefix Sums——DP/数学(组合数) CF1204E Natasha, Sasha and the Prefix Sums——DP/数学(组合数)

CF1204E Natasha, Sasha and the Prefix Sums——DP/数学(组合数)

 

题面1600174884

  CF1204E

解析

   题意就是要求所有由nn个11、mm个1−1构成的序列的最大前缀和的和

 算法一(DP)(DP)

   nn, mm都小于等于20002000, 显然可以DPDP

  设dp[i][j]dp[i][j]表示由ii个11, jj个1−1构成的序列的最大前缀和的和

  ii个11, jj个1−1构成的序列, 可以看做是在i1i−1个11, jj个1−1的序列的最前面加一个11得到,也可以看做是在ii个11, j1j−1个1−1的序列最前面加一个1−1得到

  这也就意味着,dp[i][j]dp[i][j]可以由dp[i1][j]dp[i−1][j]与dp[i][j1]dp[i][j−1]转移过来

  先考虑dp[i1][j]dp[i−1][j]对dp[i][j]dp[i][j]的贡献,对于任意一种i1i−1个11, jj个1−1的序列, 在其首端加入一个11后,最大前缀和都会加11, 序列的个数为C(i+j1,j)C(i+j−1,j),因此dp[i][j]+=dp[i1][j]+1C(ij+1,j)dp[i][j]+=dp[i−1][j]+1∗C(i−j+1,j)

  在考虑dp[i][j1]dp[i][j−1]对dp[i][j]dp[i][j]的贡献,这个和上面那个不一样,要麻烦一点。因为对于最大前缀和为00的序列,在其首端加入一个1−1后,其最大前缀和仍然是00, 所以dp[i][j]+=dp[i][j1]1(C(ij+1,j1)f[i][j1])dp[i][j]+=dp[i][j−1]−1∗(C(i−j+1,j−1)−f[i][j−1]), 其中数组f[i][j]f[i][j]表示由ii个11, jj个1−1构成的所有序列中, 最大前缀和等于00的序列个数

  因此问题变成了如何求f数组

  与求dpdp数组的思维过程类似。 ii个11, jj个1−1构成的序列, 可以看做是在i1i−1个11, jj个1−1的序列的最后面(注意这里是后面,而dpdp数组是在前面)加一个11得到,也可以看做是在ii个11, j1j−1个1−1的序列最后面加一个1−1得到

  对于ff数组,显然有iji⩽j,那么无论在序列末尾插入11或1−1,  原来最大前缀和为00的序列在插入11或1−1后,其最大前缀和依然为00,因此f[i][j]=f[i1][j]+f[i][j1]f[i][j]=f[i−1][j]+f[i][j−1]

  状态转移方程大概就是这样了

  初始化:

  f[0][i]=1(1im)f[0][i]=1(1⩽i⩽m), 其余为00

  dp[i][0]=i(1in)dp[i][0]=i(1⩽i⩽n), 其余为00

  答案就是dp[n][m]dp[n][m]

  时间复杂度O(NM)O(NM)

  在考试中我也定义出来了dpdp, ff数组, 但无论我怎么想就是想不出来转移方程, 结果方程也并不复杂, dpdp还得多加练习啊

 代码:

  View Code

算法二(数学)

   这个算法的思路很巧妙, 是从这篇博客中学来的

  如果在坐标系中把11看作是向右走一步, 1−1看作是向上走一步, 起点是(0,0)(0,0),  终点是(n,m)(n,m), 那么任意一个序列就会变成从(0,0)(0,0)出发, 只能向右或向上走,走到(n,m)(n,m)的一条路径

  设f[i]f[i]为最大前缀和大于等于i的序列个数

  那么f[i]f[i]就等于路径中存在一点(x,y)(x,y)满足如下条件的路径数,xx,yy使得ixyi⩽x−y, 即yxiy⩽x−i, (1xn,1ym)(1⩽x⩽n,1⩽y⩽m)

  结合线性规划的思想,也就是说f[i]f[i]等于路径经过直线y=xiy=x−i 及其下面区域的路径数

  考虑任意一条路径都会到(n,m)(n,m),因此当1inm1⩽i⩽n−m 时, f[i]=C(n+m,n)f[i]=C(n+m,n)

  而当max(nm,1)inmax(n−m,1)⩽i⩽n 时, 我们需要把路径转化一下,起点不再是(0,0)(0,0),而是点(0,0)(0,0)关于直线y=xiy=x−i的对称点(i,i)(i,−i),终点不变, 同样是要走n+mn+m步走到(n,m)(n,m),因为只能向右和向上走,那么就一定会经过直线y=xiy=x−i 及其下面区域。由于我们是把起点对称到了(i,i)(i,−i),所以从(i,i)(i,−i)出发经过y=xiy=x−i与从(0,0)(0,0)出发经过y=xiy=x−i两种情况的路径是映射的关系,也就是说路径是一一对应的,因此此时f[i]=C(n+m,ni)f[i]=C(n+m,n−i)。

  显然除了上述两种情况外的i, 都有f[i]=0f[i]=0

  那么最终的答案为ni=1i(f[i]f[i+1])∑i=1ni∗(f[i]−f[i+1])

  预处理阶乘与阶乘逆元,以便快速求出组合数

  时间复杂度为O(N+M)O(N+M)

  路径的转化是这种算法的关键, 也是巧妙所在

题面1600174884

  CF1204E

解析

   题意就是要求所有由nn个11、mm个1−1构成的序列的最大前缀和的和

 算法一(DP)(DP)

   nn, mm都小于等于20002000, 显然可以DPDP

  设dp[i][j]dp[i][j]表示由ii个11, jj个1−1构成的序列的最大前缀和的和

  ii个11, jj个1−1构成的序列, 可以看做是在i1i−1个11, jj个1−1的序列的最前面加一个11得到,也可以看做是在ii个11, j1j−1个1−1的序列最前面加一个1−1得到

  这也就意味着,dp[i][j]dp[i][j]可以由dp[i1][j]dp[i−1][j]与dp[i][j1]dp[i][j−1]转移过来

  先考虑dp[i1][j]dp[i−1][j]对dp[i][j]dp[i][j]的贡献,对于任意一种i1i−1个11, jj个1−1的序列, 在其首端加入一个11后,最大前缀和都会加11, 序列的个数为C(i+j1,j)C(i+j−1,j),因此dp[i][j]+=dp[i1][j]+1C(ij+1,j)dp[i][j]+=dp[i−1][j]+1∗C(i−j+1,j)

  在考虑dp[i][j1]dp[i][j−1]对dp[i][j]dp[i][j]的贡献,这个和上面那个不一样,要麻烦一点。因为对于最大前缀和为00的序列,在其首端加入一个1−1后,其最大前缀和仍然是00, 所以dp[i][j]+=dp[i][j1]1(C(ij+1,j1)f[i][j1])dp[i][j]+=dp[i][j−1]−1∗(C(i−j+1,j−1)−f[i][j−1]), 其中数组f[i][j]f[i][j]表示由ii个11, jj个1−1构成的所有序列中, 最大前缀和等于00的序列个数

  因此问题变成了如何求f数组

  与求dpdp数组的思维过程类似。 ii个11, jj个1−1构成的序列, 可以看做是在i1i−1个11, jj个1−1的序列的最后面(注意这里是后面,而dpdp数组是在前面)加一个11得到,也可以看做是在ii个11, j1j−1个1−1的序列最后面加一个1−1得到

  对于ff数组,显然有iji⩽j,那么无论在序列末尾插入11或1−1,  原来最大前缀和为00的序列在插入11或1−1后,其最大前缀和依然为00,因此f[i][j]=f[i1][j]+f[i][j1]f[i][j]=f[i−1][j]+f[i][j−1]

  状态转移方程大概就是这样了

  初始化:

  f[0][i]=1(1im)f[0][i]=1(1⩽i⩽m), 其余为00

  dp[i][0]=i(1in)dp[i][0]=i(1⩽i⩽n), 其余为00

  答案就是dp[n][m]dp[n][m]

  时间复杂度O(NM)O(NM)

  在考试中我也定义出来了dpdp, ff数组, 但无论我怎么想就是想不出来转移方程, 结果方程也并不复杂, dpdp还得多加练习啊

 代码:

  View Code

算法二(数学)

   这个算法的思路很巧妙, 是从这篇博客中学来的

  如果在坐标系中把11看作是向右走一步, 1−1看作是向上走一步, 起点是(0,0)(0,0),  终点是(n,m)(n,m), 那么任意一个序列就会变成从(0,0)(0,0)出发, 只能向右或向上走,走到(n,m)(n,m)的一条路径

  设f[i]f[i]为最大前缀和大于等于i的序列个数

  那么f[i]f[i]就等于路径中存在一点(x,y)(x,y)满足如下条件的路径数,xx,yy使得ixyi⩽x−y, 即yxiy⩽x−i, (1xn,1ym)(1⩽x⩽n,1⩽y⩽m)

  结合线性规划的思想,也就是说f[i]f[i]等于路径经过直线y=xiy=x−i 及其下面区域的路径数

  考虑任意一条路径都会到(n,m)(n,m),因此当1inm1⩽i⩽n−m 时, f[i]=C(n+m,n)f[i]=C(n+m,n)

  而当max(nm,1)inmax(n−m,1)⩽i⩽n 时, 我们需要把路径转化一下,起点不再是(0,0)(0,0),而是点(0,0)(0,0)关于直线y=xiy=x−i的对称点(i,i)(i,−i),终点不变, 同样是要走n+mn+m步走到(n,m)(n,m),因为只能向右和向上走,那么就一定会经过直线y=xiy=x−i 及其下面区域。由于我们是把起点对称到了(i,i)(i,−i),所以从(i,i)(i,−i)出发经过y=xiy=x−i与从(0,0)(0,0)出发经过y=xiy=x−i两种情况的路径是映射的关系,也就是说路径是一一对应的,因此此时f[i]=C(n+m,ni)f[i]=C(n+m,n−i)。

  显然除了上述两种情况外的i, 都有f[i]=0f[i]=0

  那么最终的答案为ni=1i(f[i]f[i+1])∑i=1ni∗(f[i]−f[i+1])

  预处理阶乘与阶乘逆元,以便快速求出组合数

  时间复杂度为O(N+M)O(N+M)

  路径的转化是这种算法的关键, 也是巧妙所在

猜你喜欢

转载自www.cnblogs.com/fsgfdsh557/p/11875012.html