Shake It!

题目传送门

前言:

好题 ,DP+组合+最大流(或者最小割)

题目大意:

给定 n , m n,m n,m,现在按照此规则生成无向图,初始我们有一张图 G G G,仅包含两个节点 s , t s,t s,t,以及连接 s → t s\to t st 的边。
每次你可以选择一条已经存在的边 ( u , v ) (u,v) (u,v),然后将往图中加入节点 w w w 和边 ( u , w ) , ( w , v ) (u,w),(w,v) (u,w),(w,v),这样操作 n n n 次,我们将得到一张图 G ′ G' G
定义 G ′ G' G 合法,当且仅当 mincut ( s , t ) = m \textrm{mincut}(s,t)=m mincut(s,t)=m,即 s → t s\to t st 的最小割为 m m m
求本质不同的合法的图 G ′ G' G 的数量,答案对 1 0 9 + 7 10^9+7 109+7 取模。
其中,两张图 G 1 , G 2 G_1,G_2 G1,G2 不同,当且仅当不存在一种作用于点集的置换,使得边对应相同,同时 s , t s,t s,t 对应相同。

解题思路:

第一眼感觉可以DP或者搜索
肯定选DP呀
于是
设计状态
直接有什么限制就设什么
f i , j 表示操作 i 次,得到的最大流为 j 的图的个数 f_{i,j}表示操作i次,得到的最大流为j的图的个数 fi,j表示操作i次,得到的最大流为j的图的个数

初始状态:
初始图的形态为
在这里插入图片描述
因此 f 0 , 1 = 1 f_{0,1}=1 f0,1=1

状态转移
考虑用 f f f转移 f f f,发现行不通,还差点东西
我们考虑,最大流由什么贡献而来,如图
在这里插入图片描述
最大流 = 1 + m i n ( x , y ) + m i n ( z , p ) , ( x , y , z , p 表示边上的流量 ) 最大流=1+min(x,y)+min(z,p),(x,y,z,p表示边上的流量) 最大流=1+min(x,y)+min(z,p),(x,y,z,p表示边上的流量)
所以最大流由两部分贡献: 1.初始的1流量
\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad 2. m i n ( 中转点到起点的流量,中转点到终点的流量 ) min(中转点到起点的流量,中转点到终点的流量) min(中转点到起点的流量,中转点到终点的流量)
所以我们设
g i , j 表示初始有 s , t , w 三个点, s − w , t − w 两条边,经过 i − 1 次(由于提前加入了 w ,所以操作次数为 i − 1 )操作后,最大流为 j 的方案数 g_{i,j}表示初始有s,t,w三个点,s-w,t-w两条边,经过i-1次(由于提前加入了w,所以操作次数为i-1)操作后,最大流为j的方案数 gi,j表示初始有s,t,w三个点,sw,tw两条边,经过i1次(由于提前加入了w,所以操作次数为i1)操作后,最大流为j的方案数
若我们已求出了 g i , j g_{i,j} gi,j,那我们可以枚举一个 t t t
f n , m < − f n − t ∗ i , m − t ∗ j ∗ C ( ) f_{n,m} <- \quad f_{n-t*i,m-t*j}*C() fn,m<fnti,mtjC(),我们再乘上一个组合数即可
这个组合数的意义就是,在选择 t t t个形如 s − w − t s-w-t swt且操作 i − 1 i-1 i1次后最大流为 j j j的方案数
我们的 g g g计算的就是供选择的集合的大小
用隔板法的思想,将 t t t个球放入 g i , j g_{i,j} gi,j个箱子
所以 f n , m < − f n − t ∗ i , m − t ∗ j ∗ C ( g i , j + t − 1 , t ) f_{n,m} <- \quad f_{n-t*i,m-t*j}*C(g_{i,j}+t-1,t) fn,m<fnti,mtjC(gi,j+t1,t)

g的转移
f f f转移g
g n , m < − ∑ i = 0 n − 1 ∑ m i n ( x , y ) = m f i , x ∗ f n − 1 − i , y g_{n,m} <- \quad \sum_{i=0}^{n-1}\sum_{min(x,y)=m}f_{i,x}*f_{n-1-i,y} gn,m<i=0n1min(x,y)=mfi,xfn1i,y
就是枚举有 i i i次操作在 s − w s-w sw上, ( n − 1 ) − i (n-1)-i (n1)i次操作在 w − t w-t wt
这个转移是 O ( n 2 ) O(n^2) O(n2),但通过处理后缀和就可以做到 O ( n ) O(n) O(n)
这是一个技巧,处理 m i n 卷积 min卷积 min卷积时都可以用,即设 f i , j ′ 为 f i , j 到 f i , n + 1 的和 f'_{i,j}为f_{i,j} 到f_{i,n+1}的和 fi,jfi,jfi,n+1的和就是后缀和的啦 然后设 g i , j ′ 也为 g 的后缀和函数 g'_{i,j}也为g的后缀和函数 gi,j也为g的后缀和函数
就有
g n , m ′ < − ∑ i = 0 n − 1 f i , m ′ ∗ f n − 1 − i , m ′ g'_{n,m}<-\quad \sum_{i=0}^{n-1}f'_{i,m}*f'_{n-1-i,m} gn,m<i=0n1fi,mfn1i,m

g g g数组差分一下 g ′ g' g即可得到

复杂度分析
枚举 g g g转移 f f f O ( n 4 ) O(n^4) O(n4)
枚举 t t t是调和级数 O ( α ) O(\alpha) O(α)
考虑最坏的情况,枚举 t t t达到 O ( ln ⁡ n ) O(\ln n) O(lnn)
总的复杂度为 O ( n 4 ln ⁡ n ) O(n^4 \ln n) O(n4lnn)

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=55,mod=1e9+7;
int n,m;
int f[N][N],g[N][N],sf[N][N],sg[N][N],inv[N];
int main() {
    scanf("%d%d",&n,&m);  f[0][1]=sf[0][1]=1;
    for(int i=(inv[0]=inv[1]=1)+1;i<=N-5;i++) 
        inv[i]=(1ll*inv[mod%i]*(mod-mod/i))%mod;
    // for(int i=1;i<=50;i++) printf("%d:%d ",i,inv[i]);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n+1;j++)
            for(int k=0;k<=i-1;k++)
                sg[i][j]=(1ll*sg[i][j]+1ll*sf[k][j]*sf[(i-1)-k][j]%mod)%mod;
        for(int j=1;j<=n+1;j++) g[i][j]=((sg[i][j]-sg[i][j+1])%mod+mod)%mod;
        for(int j=1;j<=n+1;j++){
            for(int k=n+1;k;k--) {
                for(int l=n+1;l;l--){
                    int mul=1;
                    for(int t=1;t*i<=k && t*j<=l ;t++){
                        mul=(1ll*mul*(g[i][j]+t-1)%mod*inv[t]%mod)%mod;
                        f[k][l]=(1ll*f[k][l]+1ll*f[k-t*i][l-t*j]*mul%mod)%mod;
                    }
                }
            }
        }
        for(int j=n+1;j;j--) sf[i][j]=(1ll*f[i][j]+1ll*sf[i][j+1])%mod;
    }
    printf("%d\n",f[n][m]);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值