首先这个\(60\)分的树形dp很好打,直接裸的树上背包合并即可。加了一个每次与子树大小取min的剪枝。
时间复杂度是\(O(nk^2)\)
然后写了一发过了。
然后再考虑这个东西的复杂度。
首先考虑产生\(k^2\)贡献的时候,这个显然是只有\(O(\frac{n}{k})\)次的。
然后如果是小于\(k\)合并到大于\(k\),容易发现对于小于\(k\)子树内的每个节点全程只有一次,所以是每个点均摊\(O(k)\)
如果两颗子树都小于\(k\)那么对于每个这种点的贡献是\(O(siz)\)也就是\(O(k)\)
所以时间复杂度\(O(nk)\)
code:
#include<bits/stdc++.h> #define I inline #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define abs(x) ((x)>0?(x):-(x)) #define re register #define ll long long #define db double #define N 100000 #define M 200 #define mod 1000000007 #define mod2 39989 #define eps (1e-7) #define U unsigned int #define it iterator #define Gc() getchar() #define Me(x,y) memset(x,y,sizeof(x)) using namespace std; int n,m,k,x,y,z,siz[N+5],g[M+5][4],dp[N+5][M+5][4]; struct yyy{int to,z;}; struct ljb{ int head,h[N+5];yyy f[N+5<<1]; I void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;} }s; I void dfs(int x,int last){ int i,j,h;yyy tmp;siz[x]=1;dp[x][1][0]=dp[x][0][2]=1;for(int h=s.h[x];h;h=tmp.z){ tmp=s.f[h];if(tmp.to==last) continue;dfs(tmp.to,x); for(i=0;i<=k;i++) memcpy(g[i],dp[x][i],sizeof(g[i])),Me(dp[x][i],0); for(i=min(siz[x],k);~i;i--){ for(j=0;j<=siz[tmp.to]&&j+i<=k;j++){ dp[x][i+j][0]=(dp[x][i+j][0]+1ll*g[i][0]*(dp[tmp.to][j][2]+dp[tmp.to][j][3]))%mod; dp[x][i+j][1]=(dp[x][i+j][1]+1ll*g[i][1]*(1ll*dp[tmp.to][j][0]+dp[tmp.to][j][1]+dp[tmp.to][j][2]+dp[tmp.to][j][3])+1ll*g[i][0]*(dp[tmp.to][j][1]+dp[tmp.to][j][0]))%mod; dp[x][i+j][2]=(dp[x][i+j][2]+1ll*g[i][2]*dp[tmp.to][j][3])%mod; dp[x][i+j][3]=(dp[x][i+j][3]+1ll*g[i][3]*(dp[tmp.to][j][1]+dp[tmp.to][j][3])+1ll*g[i][2]*dp[tmp.to][j][1])%mod; }//dp[x][i][0]=dp[x][i][2]=0; }siz[x]+=siz[tmp.to]; } } int main(){ freopen("disiti.in","r",stdin);freopen("disiti.out","w",stdout); re int i;scanf("%d%d",&n,&k);for(i=1;i<n;i++) scanf("%d %d",&x,&y),s.add(x,y),s.add(y,x);dfs(1,0);printf("%d\n",(dp[1][k][1]+dp[1][k][3])%mod); }