【JZOJ4816】label

Description

给出一棵树,给每个节点赋值一个 [1,m] 之间的权值,要求有边相连的两个点差绝对值 k 。求方案数,答案模 109+7

Solution

20分:

Fi,j=vsonik=1mFv,k(|kj|k)

40分:
我们发现可取 F 是连续的,维护一个前缀和即可。

100分:
找规律发现,Fi的值是对称的,且中间一大段都是相同的,那么我们只要处理 Fi 的前面一些,中间直接乘起来即可。

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<cmath>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 101
#define M 201
#define MAX 10200
#define mo 1000000007
#define ll long long
using namespace std;
int to[M],next[M],last[M],num=0;
int K;
int fa[N];
void link(int x,int y)
{
    num++;
    to[num]=y;
    next[num]=last[x];
    last[x]=num;
}
int n,m;
ll f[N][MAX],g[N][MAX],z[N][MAX];
int p[N];
int zz;
ll sum(int x,int y)
{
    if(y<=p[x]) return g[x][y];
    else if(y<=m-p[x]+1) return (g[x][p[x]]+f[x][p[x]+1]*(y-p[x])%mo)%mo;
    else return (g[x][p[x]]+f[x][p[x]+1]*(m-2*p[x])%mo+z[x][y-m+p[x]])%mo;
}
void dfs(int x)
{
    fo(i,1,zz) f[x][i]=1;
    for(int i=last[x];i;i=next[i])
    {
        int v=to[i];
        if(fa[x]!=v)
        {
            fa[v]=x;
            dfs(v);
            fo(j,1,zz)
            {
                ll tmp=0;
                tmp=(tmp+sum(v,max(j-K,0)))%mo;
                tmp=(tmp+sum(v,m)-sum(v,min(j+K,m+1)-1)+mo)%mo;
                if(!K) tmp=(tmp-f[v][j]+mo)%mo;
                f[x][j]=f[x][j]*tmp%mo;
            }
        }
    }
    fo(i,1,zz)
    if(f[x][i]==f[x][i+1]) {p[x]=i;break;}
    if(!p[x]) p[x]=zz;
    fo(i,1,zz)
    {
        g[x][i]=(g[x][i-1]+f[x][i])%mo;
        z[x][i]=(z[x][i-1]+f[x][p[x]-i+1])%mo;
    }
}
int main()
{
    freopen("label.in","r",stdin);
    freopen("label.out","w",stdout);
    int T;
    cin>>T;
    while(T--)
    {
        num=0;
        memset(last,0,sizeof(last));
        memset(p,0,sizeof(p));
        scanf("%d %d %d",&n,&m,&K);
        fo(i,1,n-1)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            link(x,y);
            link(y,x);
        }
        zz=min(m,max((n-1)*K,2));
        dfs(1);
        printf("%lld\n",sum(1,m));
    }
}
posted @ 2016-10-10 20:42  sadstone  阅读(43)  评论(0编辑  收藏  举报