NOIP提高组【JZOJ4816】label

来源:互联网 发布:美食网络营销策划案 编辑:程序博客网 时间:2024/05/02 18:42

Description

这里写图片描述

Data Constraint

这里写图片描述

Solution

我们先考虑40分的做法。显然我们设出f[i][j],表示当第i个点赋的权值为j时的方案数。那么显然这个算法的复杂度是O(N*M)的。于是我们观察f[i][j]的特殊性。我们会发现:前k* n个的方案数与后k* n个的方案数是对称的,而中间的m-2*k *n个数是相等的(其实这个用数学方法也可以证明),所以我们其实不用做m个,只用做n *k个就好,其余的对称过去,中间的算一次就好了。时间复杂度O(N2K )。

代码

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>#define ll long longusing namespace std;const int maxn=105*105,maxn1=105,mo=1000000007;ll f[maxn1][maxn],g[maxn1][maxn],n,m,x,y,i,t,j,k,l,ans,p;int first[maxn],last[maxn],next[maxn],num;bool bz;void lian(int x,int y){    last[++num]=y;next[num]=first[x];first[x]=num;}void dg(int x,int y){    int t;    for (t=first[x];t;t=next[t]){        if (last[t]==y) continue;        dg(last[t],x);        if (m>10000){            for (j=1;j<=p;j++){                if (k) f[x][j]=(g[last[t]][p-1]*2-g[last[t]][min(p-1,j+k-1)]+                g[last[t]][max((ll)0,j-k)]+f[last[t]][p]*(m-2*(p-1)-max((ll)0,j+k-p))%mo+mo)%mo*f[x][j]%mo;                else f[x][j]=f[x][j]*(g[last[t]][p-1]*2+f[last[t]][p]*(m-2*p+2)%mo)%mo;            }        }else{            for (j=1;j<=m;j++){                if (k) f[x][j]=(g[last[t]][m]-g[last[t]][min(j+k-1,m)]+g[last[t]][max(j-k,(ll)0)]+mo)%mo*f[x][j]%mo;                else f[x][j]=g[last[t]][m]*f[x][j]%mo;            }        }    }    if (m>=10000){        for (j=1;j<=p;j++)            g[x][j]=(g[x][j-1]+f[x][j])%mo;    }else{        for (j=1;j<=m;j++)            g[x][j]=(g[x][j-1]+f[x][j])%mo;    }}int main(){    freopen("label.in","r",stdin);freopen("label.out","w",stdout);    scanf("%d",&l);    while (l){        scanf("%d%d%d",&n,&m,&k);num=0;        memset(first,0,sizeof(first));bz=true;        for (i=1;i<n;i++){            scanf("%d%d",&x,&y),lian(x,y),lian(y,x);            if (x!=1 && y!=1) bz=false;        }        p=min(m,n*k);        if (m>=10000){            for (i=1;i<=n;i++)            for (j=1;j<=p;j++)                f[i][j]=1;        }else{            for (i=1;i<=n;i++)            for (j=1;j<=m;j++)                f[i][j]=1;        }        dg(1,0);if (m>10000)t=(g[1][p-1]*2+f[1][p]*(m-(p-1)*2)%mo)%mo;        else t=g[1][m];        printf("%d\n",t);        l--;    }}
3 0