jzoj6377. 【NOIP2019模拟2019.10.05】幽曲[埋骨于弘川]

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题解

真的都快忘了。
首先,我们考虑排序,求出一个神奇的排列方式,也就是dfn序。
那么答案必定是在dfn序里面一些连续的段连接起来。
然后我们就判断这玩意儿是否满足在a里面出现过。

于是现在分两步走:

第一步,假如现在有一个数字A,我们要判断其是否可以出现在a里面。
我们现在就有一种构造思路就是:从高位开始构造,假设现在构造到第i位,一直加个位之后,满足当前这位等于数字A的第i位后,继续构造第i-1位。
那么我们发现可以用一个神奇的DP来实现这个判断过程。

\(f_{i,p,x}\)表示当前做到第i位,最高位到第i位数字已经填完后最大的数字为p,个位为x开始,让第i位+1后个位变成\(f_{i,p,x}\)
这个就可以从低位开始转移到高位,每次让低位进位k次即可。注意这个p,不然会被搞崩心态。
然后再设一个\(g_{i,j,p,x}\)表示的东东和上面类似,只是这个j表示的是让第i位进位到j。
转移的话就从j-1位进过去,利用f数值即可。

第二步,开始统计答案。
我们设\(dp_{i,j,p,x}\)表示当前走到dfn序中的第i位,当前弄出来的数字是第j位,且当前位置放的是\(d[dfn[i]]\),最大值为p,各位从x开始的方案数。
我们发现,这个i是可以从\(fa_i\)\(i\)这一段区间内转移过来的。
所以说,我们可以利用前缀和优化一下,时间复杂度就变成\(O(n^2*k^2)\)

小细节巨多无比。

标程

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cctype>
using namespace std;
const long long mo=998244353;
const int maxn=501;
const int maxm=11;

int n,m,a[maxn],x[maxn],y[maxn],gs;
int f[maxn][maxm][maxm];
int g[maxn][maxm][maxm][maxm];
long long dp[maxn][maxn][maxm][maxm],sum[maxn][maxn][maxm][maxm];
int tot,nex[maxn*2],las[maxn*2],tov[maxn*2];
int dfn[maxn],wz[maxn],fa[maxn],dep;
int tot1,nex1[maxn*2],las1[maxn*2],tov1[maxn*2];
int son[maxn][maxn];

__attribute__((optimize("-O3")))
void qsort(int x,int l,int r)
{
    int i=l;int j=r;
    int m=son[x][(i+j)/2];
    while (i<=j)
    {
        while (son[x][i]>m) i++;
        while (son[x][j]<m) j--;
        if (i<=j)
        {
            swap(son[x][i],son[x][j]);
            i++;j--;
        }
    }
    if (l<j) qsort(x,l,j);
    if (r>i) qsort(x,i,r); 
}

__attribute__((optimize("-O3")))
void insert(int x,int y)
{
    tot++;
    tov[tot]=y;
    nex[tot]=las[x];
    las[x]=tot;
}

__attribute__((optimize("-O3")))
void insert1(int x,int y)
{
    tot1++;
    tov1[tot1]=y;
    nex1[tot1]=las1[x];
    las1[x]=tot1;
}

__attribute__((optimize("-O3")))
void dfs(int x,int ff)
{
    gs++;
    dfn[x]=gs;
    wz[gs]=x;
    for (int i=las1[x];i>0;i=nex1[i])
    {
        if (tov1[i]!=ff)
        {
            fa[tov1[i]]=x;
            dfs(tov1[i],x);
        }
    }
}

__attribute__((optimize("-O3")))
void dfssort(int x,int ff)
{
    for (int i=las[x];i>0;i=nex[i])
    {
        if (tov[i]!=ff)
        {
            son[x][0]++;
            son[x][son[x][0]]=tov[i];
            dfssort(tov[i],x);
        }
    }
    qsort(x,1,son[x][0]);
    for (int i=1;i<=son[x][0];i++)
    {
        insert1(x,son[x][i]);
        insert1(son[x][i],x);
    }
}

__attribute__((optimize("-O3")))
int main()
{
//  freopen("data.in","r",stdin);
    freopen("buried.in","r",stdin);
    freopen("buried.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (register int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    for (register int i=1;i<n;i++)
    {
        scanf("%d%d",&x[i],&y[i]);
        insert(x[i],y[i]);
        insert(y[i],x[i]);
    }
    dfssort(1,0);
    dfs(1,0);
    for (register int i=1;i<=n;i++)
    {
        for (register int p=0;p<m;p++)
        {
            for (register int x=0;x<m;x++)
            {
                f[i][p][x]=-1;
                for (register int a=0;a<m;a++)
                {
                    g[i][p][a][x]=-1;
                }
            }
        }
    }
    for (register int i=0;i<m;i++)
    {
        for (register int x=0;x<m;x++)
        {
            if (i>0 || (i==0 && x>0))
            {
                register int j=x;
                while (j<m)
                {
                    g[1][i][j][x]=j;
                    j=j+max(j,i);
                }
                f[1][i][x]=j%m;
                g[2][i][1][x]=j%m;
            }
        }
    }
    for (register int i=0;i<m;i++)
    {
        for (register int x=0;x<m;x++)
        {
            g[2][i][0][x]=x;
            if (i>0 || (i==0 && x>0))
            {
                register int j=f[1][i][x];
                for (register int cs=2;cs<m;cs++)
                {
                    g[2][i][cs][x]=f[1][max(i,cs-1)][j];
                    j=f[1][max(i,cs-1)][j];
                }
            }
        }
    }
    
    for (register int i=2;i<=n;i++)
    {
        for (register int p=0;p<m;p++)
        {
            for (register int x=0;x<m;x++)
            {
                if (p>0 || (p==0 && x>0))
                {
                    register int op=x;
                    g[i][p][0][x]=x;
                    for (register int j=0;j<m;j++)
                    {
                        op=f[i-1][max(p,j)][op];
                        if (j<m-1) g[i][p][j+1][x]=op;
                    }
                    f[i][p][x]=op;
                }
            }
        }
    }
    for (register int i=3;i<=n;i++)
    {
        for (register int p=0;p<m;p++)
        {
            for (register int x=0;x<m;x++)
            {
                if (p>0 || (p==0 && x>0))
                {
                    register int op=f[i-2][m-1][g[i-1][p][m-1][x]];
                    g[i][p][1][x]=op;
                }
            }
        }
    }
    for (register int i=3;i<=n;i++)
    {
        for (register int p=0;p<m;p++)
        {
            for (register int x=0;x<m;x++)
            {
                g[i][p][0][x]=x;
                if (p>0 || (p==0 && x>0))
                {
                    register int j=g[i][p][1][x];
                    for (register int cs=2;cs<m;cs++)
                    {
                        g[i][p][cs][x]=f[i-1][max(p,cs-1)][j];
                        j=f[i-1][max(p,cs-1)][j];
                    }
                }
            }
        }
    }
    
    for (register int i=1;i<=n;i++)
    {
        dp[1][i][a[1]][g[i][0][a[1]][1]]=1;
        sum[1][i][a[1]][g[i][0][a[1]][1]]=1;
    }
    for (register int i=2;i<=n;i++)
    {
        for (register int p=0;p<m;p++)
        {
            for (register int x=0;x<m;x++)
            {
                for (register int w=1;w<=n-i+1;w++)
                {
                    if (g[w][p][a[wz[i]]][x]>=0)
                    {
                        dp[i][w][max(p,a[wz[i]])][g[w][p][a[wz[i]]][x]]=
                        (dp[i][w][max(p,a[wz[i]])][g[w][p][a[wz[i]]][x]]+sum[i-1][w+1][p][x]-sum[dfn[fa[wz[i]]]-1][w+1][p][x]+mo)%mo;
                    }
                }
            }
        } 
        memcpy(sum[i],sum[i-1],sizeof(sum[i-1]));
        for (register int w=1;w<=n-i+1;w++)
        {
            for (register int x=0;x<m;x++)
            {
                for (register int p=0;p<m;p++)
                {
                //  if (g[w][p][a[wz[i]]][x]>=0)
                    {
                        sum[i][w][p][x]=
                        (sum[i][w][p][x]+dp[i][w][p][x])%mo;
                    }
                }
            }
        } 
    }
    long long ans=0;
    for (register int i=1;i<=n;i++)
    {
        for (register int j=a[wz[i]];j<m;j++)
        {
            ans=(ans+dp[i][1][j][a[wz[i]]])%mo;
        }
    }
    printf("%lld\n",ans);
}

猜你喜欢

转载自www.cnblogs.com/RainbowCrown/p/11721071.html
今日推荐