[]ラベル[NOIP2016 JZOJ4816 Aグループ5校の入学試験4を向上させます]

タイトル効果:ある\(N- \)ツリーポイント、アサインA得各点\([1、m]が\ ) 少なくともの差は、重み内の値の整数ので、2つの隣接する右小数点値その\(K \) いくつかのプログラムをお願いします。
\(N、K \当量100 、M \当量10 ^ 9 \)

溶液

セット\(F [I] [jを ] \) を表し(I \)\サブツリーのルートと条件を満たす、および\(I \)重み値\(J \)プログラム番号、およびプレフィックス最適化転送。
テーブルを再生することにより、見つけることができます\(F [i]の[jは ] \) 対称である、すなわち\(F [I] [J] = F [I] [M-J + 1] \) およびに委ね\ ((N-1)* K \) 異なる数、中央部が同じです。我々は前に記録よう\((N-1)* K \) 状態、および\(POS [I] \)同一であるから、開始を表し、することができるであろう\(O(1)\)決定されますそして、プレフィックス。

コード

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long ll;
const int N=107,M=10017;
const ll P=1000000007;

int T,n,m,k;
ll f[N][M],s[N][M],pos[N];

int tot,st[N],to[N<<1],nx[N<<1];
void add(int u,int v){to[++tot]=v,nx[tot]=st[u],st[u]=tot;}

ll sum(int u,int j){
    ll ret=0;
    if(j<=10010)return s[u][j];
    else if(j<pos[u])return s[u][j];
    else{
        ret=(ret+s[u][pos[u]-1])%P;
        if(j<=m-pos[u]+1)ret=(ret+f[u][pos[u]]*(j-pos[u]+1)%P)%P;
        else{
            ret=(ret+f[u][pos[u]]*(m-2*pos[u]+2)%P)%P;
            ret=(ret+s[u][pos[u]-1]-s[u][m-j]+P)%P;
        }
        return ret;
    }
}

void dfs(int u,int from){
    for(int i=st[u];i;i=nx[i])if(to[i]!=from)dfs(to[i],u);
    for(int j=1;j<=10010&&j<=m;++j){
        f[u][j]=1;
        for(int i=st[u];i;i=nx[i])if(to[i]!=from){
            if(k==0)f[u][j]=f[u][j]*sum(to[i],m)%P;
            else{
                ll tmp=0;
                if(j-k>0)tmp=(tmp+sum(to[i],j-k))%P;
                if(j+k<=m)tmp=(tmp+sum(to[i],m)-sum(to[i],j+k-1)+P)%P;
                f[u][j]=f[u][j]*tmp%P;
            }
        }
    }
    for(int j=1;j<=10010&&j<=m;++j)if(f[u][j]==f[u][j+1]){pos[u]=j;break;}
    for(int j=1;j<=10010&&j<=m;++j)s[u][j]=(s[u][j-1]+f[u][j])%P;
}

int main(){
    freopen("label.in","r",stdin);
    //freopen("label.out","w",stdout);
    scanf("%d",&T);
    while(T--){
        tot=0;
        memset(st,0,sizeof(st));
        memset(f,0,sizeof(f));
        memset(s,0,sizeof(s));
        memset(pos,0,sizeof(pos));
        memset(to,0,sizeof(to));
        memset(nx,0,sizeof(nx));
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1,u,v;i<n;++i)scanf("%d%d",&u,&v),add(u,v),add(v,u);
        dfs(1,0);
        printf("%lld\n",sum(1,m));
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/zjlcnblogs/p/12055053.html