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

Problem

Description
这里写图片描述
Input
这里写图片描述
Output
这里写图片描述
Sample Input
3
2 2 0
1 2
3 3 2
1 3
1 2
3 3 1
1 2
2 3
Sample Output
4
2
12
Data Constraint
这里写图片描述
Hint
这里写图片描述

Solution

果断树形DP。
首先我们先过前20%40%数据。
Fx,y 表示x号点取y所满足的方案数。
易得方程

Fx,y=ΠvsonxΣFv,i(|iy|k)

对于 40%数据,可以发现有一段 Fv,i 连续相等。
于是我们维护一个前缀和就行了。
接下来我们该考虑如何 切掉这题。
我们发现,同一个 x <script type="math/tex" id="MathJax-Element-270">x</script>对应的DP值是对称的。然后中间有一段DP值是相同的。
然后我们分类讨论去求其值就行了。
这里写图片描述

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define N 110
#define LL long long
#define mo 1000000007
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
LL a[N][N],b[N][N],deep[N],d[N],f[N][30010],sum[N][30010];
LL _,mx,i,j,n,m,k,x,y,wz,tot,ans;
bool bz[N];
LL ges(LL x,LL j)
{
    if (j<=wz) return sum[x][j];else
    if (j<=m-wz) return (sum[x][wz]+(j-wz)*f[x][wz+1])%mo;else
    {
        LL temp;
        temp=(sum[x][wz]-sum[x][m-j]+mo)%mo;
        temp=(temp+(sum[x][wz]+(m-wz*2+mo)*f[x][wz+1])%mo)%mo;
        return temp;
    }
}
LL ksm(LL x,LL p)
{
    LL s=1;
    while (p)
    {
        if (p%2) s=(s*x)%mo;
        x=(x*x)%mo;
        p/=2;
    }
    return s;
}
void dg(LL k,LL fa)
{
    LL i;
    fo(i,1,a[k][0])
    {
        if (a[k][i]==fa) continue;
        deep[a[k][i]]=deep[k]+1;
        dg(a[k][i],k);
    }
}
void dfs(LL x)
{
    LL i,j,y,now,p;
    bz[x]=1;
    fo(i,1,b[x][0])
    {
        if (bz[b[x][i]]) continue;
        dfs(b[x][i]);
        fo(y,1,wz+1)
        {
            p=0;
            if (y-k>=0) p=ges(b[x][i],y-k);
            if (y+k<=m) p=(p+ges(b[x][i],m)-ges(b[x][i],y+k-1)+mo)%mo;
            if (!k) p=(p-ges(b[x][i],y)+ges(b[x][i],y-1)+mo)%mo;
            f[x][y]=(f[x][y]*p)%mo;
        }
        sum[x][0]=0;
        fo(y,1,wz+1) sum[x][y]=(sum[x][y-1]+f[x][y])%mo;
    }
}
int main()
{
    freopen("label.in","r",stdin);
    freopen("label.out","w",stdout);
    scanf("%lld",&_);
    while (_--)
    {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        memset(deep,0,sizeof(deep));
        memset(bz,0,sizeof(bz));
        scanf("%lld%lld%lld",&n,&m,&k);
        if (m<=9901) wz=m;else wz=(n-1)*k+1;
        fo(i,1,n-1)
        {
            scanf("%lld%lld",&x,&y);
            a[x][++a[x][0]]=y;
            a[y][++a[y][0]]=x;
        }
        dg(1,0);
        fo(i,1,n) fo(j,1,30009) f[i][j]=1,sum[i][j]=sum[i][j-1]+f[i][j];
        fo(i,1,n)
            fo(j,1,a[i][0])
                if (deep[i]<deep[a[i][j]]) b[i][++b[i][0]]=a[i][j];
        dfs(1);
        ans=ges(1,m);
        printf("%lld\n",ans);
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值