[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}$是枚举连通块,另一个n是hash的时间),显然这样是会炸掉的……
似乎这个状态的记录方式可以改变,可改为每一个大小的连通块出现次数,由于最多只有$\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 }