【JZOJ 4816】【NOIP2016提高组 五校联考4】label

来源:互联网 发布:搜狗输入法mac版本 编辑:程序博客网 时间:2024/05/21 19:21

Description

这里写图片描述
这里写图片描述

Analysis

首先,40分的dp很容易想,设f[i][j]表示给i的子树做完,给i赋j的方案数。

f[i][j]=vson(i)f[v][x](|xj|k)

随便乱搞些东西就有60~80分了。
然后有一个很显然却容易忽视的性质:f[i]是对称的。
而且中间有一大段的值是一样的!
可以证明(思考一下),因为 k<=100,所以 dp 值一端最多只有 99*100 个不同的。
所以只需要记录这么多个DP值,可以快速的算出来。

Code

#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,b,a) for(int i=b;i>=a;i--)#define efo(i,v) for(int i=last[v];i;i=next[i])using namespace std;typedef long long ll;const int N=110,M=10010,mo=1e9+7;int n,m,LYD,k,tot,to[N*2],next[N*2],last[N];ll f[N][M],sum[N][M];void link(int u,int v){    to[++tot]=v,next[tot]=last[u],last[u]=tot;}ll s(int v,int x){    if(x<=LYD) return sum[v][min(x,LYD)];    if(x<=m-LYD) return (sum[v][LYD]+(x-LYD)*f[v][LYD+1]%mo)%mo;    return (sum[v][LYD]+f[v][LYD+1]*(m-2*LYD)%mo+sum[v][LYD]-sum[v][m-x]+mo)%mo;}void dfs(int v,int fr){    fo(i,1,LYD+1) f[v][i]=1;    efo(i,v)    {        int u=to[i];        if(u==fr) continue;        dfs(u,v);        fo(j,1,LYD+1)        {            ll t=0;            if(j-k>0) t=s(u,j-k);            if(j+k<=m) t=(t+s(u,m)-s(u,j+k-1)+mo)%mo;            if(!k) t=(t-f[u][j]+mo)%mo;            (f[v][j]*=t)%=mo;        }    }    fo(i,1,LYD+1) sum[v][i]=(sum[v][i-1]+f[v][i])%mo;}int main(){    freopen("label.in","r",stdin);    freopen("label.out","w",stdout);    int _,u,v;    for(scanf("%d",&_);_--;)    {        memset(f,0,sizeof(f));        memset(sum,0,sizeof(sum));        tot=0;        memset(last,0,sizeof(last));        scanf("%d %d %d",&n,&m,&k);        fo(i,1,n-1)        {            scanf("%d %d",&u,&v);            link(u,v),link(v,u);        }        LYD=min(m,10000);        dfs(1,1);        printf("%lld\n",s(1,m));    }    return 0;}
0 0