zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    }
    
  • 相关阅读:
    bzoj 2527: [Poi2011]Meteors 整体二分
    bzoj 2738 矩阵乘法
    bzoj 3110 K大数查询
    bzoj 3262 陌上花开
    cogs 577 蝗灾 CDQ分治
    bzoj 1101 zap
    bzoj 2005
    bzoj 3518 Dirichlet卷积
    bzoj 1257
    最优贸易 [NOIP 2009]
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11721071.html
Copyright © 2011-2022 走看看