[noi31]MST

定义dp[i]表示当前连通块状态为i的方案数(状态记录该状态每一个连通块的大小),那么从小到大枚举每条边,考虑这条边在不在最小生成树上:

1. 如果不在最小生成树上,那么这条边有$\sum_{i=1}^{scc}\sum_{j=i+1}^{scc}Si\cdot Sj$Si表示第i个连通块的点数)种位置,即每一个状态的方案都乘上这个数;

2. 如果在最小生成树上,那么他一定会把某两个连通块连起来,枚举这两个连通块并递推到新的状态。

那么这样的时间复杂度是多少呢?大约是$o(Pn\cdot n^{3})$Pn表示将n划分成一些数的和的方案数,$P_{40}\approx 40000$,$n^{2}$是枚举连通块,另一个nhash的时间),显然这样是会炸掉的……

似乎这个状态的记录方式可以改变,可改为每一个大小的连通块出现次数,由于最多只有$\sqrt{n}$种方案,枚举两个连通块也仅有n的时间复杂度,总时间复杂度降为$o(Pn\cdot n^{2})$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define mod 1000000007
 4 map<int,int>vis;
 5 int n,m,k,di[40001][41],a[41],mi[41],b[1001],f[40001];
 6 vector<int>vec[40001];
 7 void dfs(int k,int s,int p){
 8     if (!s){
 9         memcpy(di[++m],a,sizeof(a));
10         di[m][0]=k;
11     }
12     if (s<1)return;
13     k++;
14     for(int i=1;i<=p;i++){
15         a[i]++;
16         dfs(k,s-i,i);
17         a[i]--;
18     }
19 }
20 int ha(int k){
21     int ans=0;
22     for(int i=1;i<=n;i++)ans=(ans+1LL*mi[i]*di[k][i])%mod;
23     return ans;
24 }
25 int main(){
26     mi[0]=1;
27     for(int i=1;i<=40;i++)mi[i]=mi[i-1]*41LL%mod; 
28     scanf("%d",&n);
29     dfs(0,n,n);
30     for(int i=1;i<=m;i++)vec[di[i][0]].push_back(i);
31     for(int i=1;i<n;i++){
32         scanf("%d",&k);
33         b[k]=1;
34     }
35     f[1]=1;
36     m=n*(n-1)/2;
37     k=n;
38     for(int i=1;i<=m;i++)
39         if (!b[i])
40             for(int j=0;j<vec[k].size();j++){
41                 int v=vec[k][j],s=m-i+1;
42                 for(int x=1;x<=n;x++)
43                     for(int y=x+1;y<=n;y++)s-=di[v][x]*di[v][y]*x*y;
44                 for(int x=1;x<=n;x++)s-=(di[v][x]-1)*di[v][x]*x*x/2;
45                 f[vec[k][j]]=f[vec[k][j]]*1LL*s%mod; 
46             }
47         else{
48             for(int j=0;j<vec[k-1].size();j++)vis[ha(vec[k-1][j])]=vec[k-1][j];
49             for(int j=0;j<vec[k].size();j++){
50                 int v=vec[k][j];
51                 for(int x=1;x<=n;x++)
52                     for(int y=x+1;y<=n-x;y++){
53                         if ((!di[v][x])||(!di[v][y]))continue;
54                         di[v][x]--;
55                         di[v][y]--;
56                         di[v][x+y]++;
57                         f[vis[ha(v)]]=(f[vis[ha(v)]]+f[v]*(di[v][x]+1LL)*(di[v][y]+1)*x*y)%mod;
58                         di[v][x]++;
59                         di[v][y]++;
60                         di[v][x+y]--;
61                     }
62                 for(int x=1;x<=n/2;x++)
63                     if (di[v][x]>1){
64                         di[v][x]-=2;
65                         di[v][x+x]++;
66                         f[vis[ha(v)]]=(f[vis[ha(v)]]+f[v]*(di[v][x]+2LL)*(di[v][x]+1)*x*x/2)%mod;
67                         di[v][x]+=2;
68                         di[v][x+x]--;
69                     }
70             }
71             k--;
72             for(int j=0;j<vec[k].size();j++)vis[ha(vec[k][j])]=0;
73         }
74     printf("%d",f[vec[1][0]]);
75 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/11272189.html