列表

详情


NC21122. [NOI2018]多边形

描述

久莲是一个喜欢出题的女孩子。 
在今年的 World Final 结束以后,久莲特别喜欢计算几何,于是她打算在 NOI 的 考场上也出一个计算几何:这是一道只有题目名字和计算几何相关的题目。
首先,久莲给出了一棵 n(n ≥ 2) 个节点的有根树 T,根节点编号为 1。定义叶子节 点为除了根以外所有度数恰好为 1 的节点。下图是一个树 T 的例子,其中叶子节点集 合为 {3, 4, 5}。
 
接着通过这棵树,久莲构造了一个序列 A: 
• 从根节点开始深度优先遍历整棵树,遍历时按照编号从小到大的顺序来访问孩 子,这样可以得到一个树 T 的 DFS 序。
• 接着按照在 DFS 序中的出现顺序从前往后,久莲把所有叶子节点排成一排得到 了一个序列 A。 
更进一步地,通过序列 A,久莲定义了两个叶子节点 u, v 的距离 d(u, v):
假设 u 在 A 中是第 i 个元素,v 是第 j 个元素,则 d(u, v) = min(|i − j|, |A| − |i − j|)。其中 |A| 为序 列的长度,即 T 的叶子个数,i, j 指的是出现的位置,从 1 开始计数。 
上面的例子中,序列 A 为 [4, 5, 3],其中 d(3, 5) = d(3, 4) = d(4, 5) = 1,3, 4, 5 的出 现位置分别为 3, 1, 2。 
最后,久莲给出了一个参数 K,利用这棵有根树 T 和序列 A,我们可以构造一张 n 个点的无. 重. 边. 无. 自. 环. 的无向图 G:两个不同的点 u, v 之间有边当且仅当它们满足下列 条件中的至少一个: 
• 在树 T 中存在连接 u, v 的边。
• 在树 T 中 u, v 都是叶子节点且 d(u, v) ≤ K。 当 K = 1 或 2 时,上面的例子得到的图 G 都如下图所示: 现在久莲想让你来计算一下 G 中不同的哈密尔顿回路数量有多少条,答案可能很 大,请对 998244353 取模后输出。 

下面是一些补充定义:
 • 无重边无自环的无向图 G 的一条哈密尔顿回路 H 是 G 中边的一个子集,其中 每一个点恰好有两条不同的相邻边在 H 中,且任意两个点都可以通过 H 中的边 直接或间接到达。
 • 无重边无自环的无向图 G 的两条哈密尔顿回路 H1, H2 是不同的当且仅当存在一 条边 e 使得 e 在 H1 中且不在 H2 中。 

输入描述

第一行输入两个整数 n, K,表示树 T 的点数以及久莲选定的参数 K。
第二行输入 n − 1 个整数 fi(1 ≤ fi ≤ i),其中 fi 表示树 T 上存在边 (fi
, i + 1)。

输出描述

输出一行一个整数,表示哈密尔顿回路数量对 998244353 取模后的结果。

示例1

输入:

5 1
1 1 2 2

输出:

2

说明:

该样例和题面中的例子完全相同。两条哈密尔顿回路经过节点的顺序分别为
(1, 2, 4, 5, 3) 和 (1, 2, 5, 4, 3)。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++ 11.0.1) 解法, 执行用时: 1715ms, 内存消耗: 199028K, 提交时间: 2022-12-11 15:11:19

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<iostream>
#include<map>
#include<cstring>
#define ll long long
#define maxn 1005
#define p 998244353 
#define re(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
inline int read(){char c=getchar();int f=1;int ans = 0;while(c>'9'||c<'0'){if(c=='-')f=-f;c=getchar();}while(c<='9'&&c>='0'){ans =ans*10+c-'0';c=getchar();}return ans*f;}
//_____________________________________________________________________________________________________
int k,used[maxn],_n,n,m,_a[maxn][maxn],__a[maxn][maxn],leaf[maxn],_st[maxn];
ll ans;
inline int dfs1(int x)//缩链
{
    int cnt = 0,y;
    re(i,1,_n)
        if(_a[x][i])
            cnt++;
    if(cnt==1)
    {
        re(i,1,_n)
            if(_a[x][i])
                return dfs1(i);
    }
    used[x] = 1;
    if(!cnt)
    {
        _st[++_st[0]] = ++n;
        leaf[n]=1;
        return n;
    }
    int _x = ++n;
    re(i,1,_n)
        if(_a[x][i])
        {
            int y = dfs1(i);
            leaf[_x] += leaf[y] ;
            if(used[i])
                __a[_x][y] = 1;
            else
            {
                leaf[++n] = leaf[y];
                __a[_x][n] = __a[n][y] = 1;
            }
        }
    return _x; 
}
inline void build()
{
    re(i,1,_n)
        if(_a[1][i])
        {
            int y = dfs1(i);
            leaf[1] += leaf[y];
            if(used[i])
                __a[1][y] = 1;
            else
            {
                leaf[++n]=leaf[y];
                __a[1][n] = __a[n][y] = 1;
            }
        }
}
int __dp[1<<21][25];
inline void solve1()//暴力
{
    ans = 0;
    re(i,1,_st[0])
        re(j,1,k)
            __a[ _st[i] ][ _st[ i+j>_st[0] ? i+j-_st[0] : i+j ] ] = 1;
    re(i,1,n)
        re(j,1,n)
            if(__a[i][j])
                __a[j][i] = 1;
    int S = (1<<n)-1;__dp[1][1] = 1;
    for(int s=1;s<=S;s+=2)
        re(x,1,n)
            if(__dp[s][x]&&((s>>x-1)&1))
                re(y,1,n)
                    if(__a[x][y]&&(((s>>y-1)&1)==0))
                        (__dp[ s|(1<<y-1) ][y] += __dp[s][x])%=p;
    re(i,1,n)
        if(__a[1][i])
            (ans+=__dp[S][i])%=p;
    printf("%d\n",ans*(p+1)/2%p);
}
//______________________________________________
int match[40];
struct node
{
    int len,root;
    int s[13];
    inline void clear()
    {
        re(i,1,13)
            s[i] = 0;
        len = root = 0;
    }
    void pri()
    {
        printf("%d|",root);
        re(i,1,len)
            printf("%d ",s[i]);
        printf("\n________________________\n");
    };
    inline bool operator <(node x)const
    {
        if(root!=x.root ) return root<x.root ;
        if(len!=x.len) return len<x.len ;
        re(i,1,len)
            if(s[i]!=x.s [i])
                return s[i] < x.s [i];
        return false;
    }
    inline void sort(int sz)
    {
        int cnt = 1;
        re(i,2,sz)
            match[i] = 0;
        re(i,1,len)
            if( s[i]>1 )
            {
                if( match[s[i]] )
                    s[i] = match[s[i]];
                else
                    s[i] = match[s[i]] = ++cnt;
            }
    }
}node1,a[maxn*40];
map<node,int> mp;
int tot;
void dfs2(int i,int cnt)
{
    if(i==node1.len +1)
    {
        re(j,1,node1.len )
            if(node1.s [j])
            {
                a[++tot] = node1;
                mp[node1] = tot;
                break;
            }
        return ;
    }
    dfs2(i+1,cnt);
    if(!node1.s [i])
    {
        node1.s[i] = cnt+1;
        re(j,i+1,node1.len )
            if(!node1.s [j])
            {
                node1.s [j] = cnt+1;
                dfs2(i+1,cnt+1);
                node1.s [j] = 0;
            }
        node1.s [i] = 0; 
    }
}
struct turn
{
    int x,y,to;
    turn(int x=0,int y=0,int to=0)
    :x(x),y(y),to(to){};
}f[7][7][210000];
int tot_f[7][7];
#define pr pair<int,int> 
int st1[maxn*200],_st2;
pr st2[maxn*200];
inline void check(node x,int cnt)
{
    re(i,k+1,x.len-k)
        if(x.s [i])
            return;
    node1.clear(); 
    if(x.len>2*k)
    {
        node1.root = x.root ;
        node1.len = 2*k;
        re(i,1,k)
            node1.s [i] = x.s[i];
        re(i,x.len -k+1,x.len )
            node1.s [i- x.len  + 2*k] = x.s[i] ;
    }
    else node1 = x; 
    node1.sort(cnt);
    if( mp[node1]!=0 )
        st1[++st1[0]] = mp[node1];
}
int vis[20];
inline void dfs3(int i,int lim,node x,int cnt)
{
    if(i==lim+1)
    {
        check(x,cnt+1);
        return ;
    }
    dfs3(i+1,lim,x,cnt+1);
    if(x.s [i]>0)
        re(j,lim+1,min(x.len ,i+k))
        {
            int n_col = x.s [j]==1 || x.s[i] == 1 ? 1 : cnt+1;
            if(x.s [j]>0&&(x.s [j]!=x.s [i]||x.s[j]==1 ))
            {
                node1 = x;
                re(t,1,x.len )
                    if( x.s [t] == x.s [i] || x.s [t]==x.s [j] )
                        node1.s[t] = n_col;	
                node1.s [i] = node1.s [j] = 0;			
                dfs3(i+1,lim,node1,cnt+1);
            }
            if(x.s [j]==-1)
            {
                node1 = x;	
                node1.s [j] = node1.s [i];
                node1.s [i] = 0;
                dfs3(i+1,lim,node1,cnt+1);
            }
        }
    if(x.s [i]==-1)
        re(j,lim+1,min(x.len,i+k))
            if(x.s [j])
            {
                node1  = x;
                if(x.s [j]==-1)
                    node1.s [i] = node1.s [j] = cnt+1;
                else 
                    node1.s [i] = node1.s [j],
                    node1.s [j] = 0;
                dfs3(i+1,lim,node1,cnt+1);
                re(t,j+1,min(x.len,i+k))
                    if(x.s[t]==-1 ||(x.s[t]>0&&(x.s[t]!=x.s[j] || x.s[t]==1)))  
                    {
                        node1 = x;
                        node1.s [i] = 0;
                        if( x.s[j]==-1 && x.s[t] ==-1 )
                            node1.s [j] = node1.s [t] = cnt+1 ;
                        if( x.s[j]==-1 && x.s[t]!=-1)
                            node1.s [j] = node1.s [t] , node1.s [t] = 0;
                        if( x.s [j]!=-1&& x.s[t]==-1)
                            node1.s [t] = node1.s [j] , node1.s [j] = 0;
                        if( x.s [j]!=-1&&x.s[t]!=-1)
                        {
                            int n_col = x.s [j]==1 || x.s[t] == 1 ? 1 : cnt+1;
                            re(_t,1,x.len)
                                if(x.s[_t]==x.s[j]|| x.s[_t] == x.s[t] )
                                    node1.s [_t] = n_col ;
                            node1.s [j] = node1.s [t] = 0;
                        }
                        dfs3(i+1,lim,node1,cnt+1);	
                    }
            }
}
inline void Turn(node l,node r)
{
    if(l.root + r.root > 2)
        return;
    node1.clear();
    re(i,1,l.len )
        node1.s[i] = l.s [i];
    re(i,1,r.len )
        node1.s [ i+l.len ] = r.s [i] <=1 ? r.s [i] : r.s [i] + k ;
    node1.root = l.root + r.root ;
    node1.len = l.len + r.len ;
    dfs3( max(1,l.len -k+1),l.len , node1 ,2*k+1 );
}
inline int _Turn(int x)
{
    if(a[x].root == 0)
        return 0;
    if(a[x].root == 1)
        return x;
    node1 = a[x];
    node1.root = 0;
    re(i,1,node1.len )
        if(node1.s [i]==1)
            node1.s [i] = k+2;
    node1.sort(k+2);
    return mp[node1];
}
pr _f[maxn*40];int _tot_f,cnt_5;
ll dp[maxn][maxn*3],_dp[maxn*3];
inline ll count(int i,node x,int col)
{
    if(x.len !=2*k || x.root !=2)
        return 0;
    if(i==k+1)
    {
        re(t,1,2*k)
            if(x.s[t])
                return 0;
        return 1;
    }
    int cnt = 0;
    if(!x.s[i])
        cnt = count(i+1,x,col);
    if(x.s[i]>0)
        re(j,k+i,2*k)
            if(x.s[j])
            {
                node1 = x;
                if( x.s[j]>0 &&( x.s [j]==1 ||  x.s[i] !=x .s[j]))
                {
                    int n_col = x.s [i]==1 || x.s [j] ==1 ? 1 : col +1;
                    re(t,1,2*k)
                        if( x.s [t] == x.s[i] || x.s[t]== x.s[j] )
                            node1.s [t] = n_col;
                    node1.s [i] = node1.s [j] = 0;
                    cnt += count(i+1,node1,col+1);
                }
                if( x.s[j]==-1 )
                {
                    node1.s [j] =  node1.s [i];
                    node1.s [i] = 0;
                    cnt += count(i+1,node1,col+1);
                }
            }
    if(x.s[i]==-1)
    {
        re(j,k+i,2*k)
            if(x.s[j])
            {
                re(t,j+1,2*k)
                {
                    node1  =x;
                    if( x.s[t]==-1 ||(x.s[t]>0 && (x.s[t]==1|| x.s[t]!=x.s[j] )))
                    {
                        node1.s [i] = 0;
                        if( x.s[j]==-1 && x.s[t] ==-1 )
                            node1.s [j] = node1.s [t] = col+1;
                        if( x.s[j]==-1 && x.s[t]!=-1)
                            node1.s [j] = node1.s [t] , node1.s [t] = 0;
                        if( x.s [j]!=-1&& x.s[t]==-1)
                            node1.s [t] = node1.s [j] , node1.s [j] = 0;
                        if( x.s [j]!=-1&&x.s[t]!=-1)
                        {
                            int n_col = x.s [j]==1 || x.s[t] == 1 ? 1 : cnt+1;
                            re(_t,1,x.len)
                                    if(x.s[_t]==x.s[j]||x.s[_t]==x.s[t])
                                        node1.s [_t] = n_col ;
                            node1.s [j] = node1.s [t] = 0;
                        }
                        cnt += count( i+1,node1,col+1 );
                    }
                }
            }
    }
    return cnt;	
}
void dfs4(int x)
{
    int bo = 0,cnt_leaf=0;
    re(y,1,n)
        if(__a[x][y])
        {
            dfs4(y);
            if(!bo)
            {
                memcpy(dp[x],dp[y],sizeof(dp[x]));
                bo = 1;
                cnt_leaf = leaf[y];
            }
            else 
            {
                memcpy(_dp,dp[x],sizeof(_dp));
                memset(dp[x],0,sizeof(dp[x]));
                re(t,1,tot_f[ cnt_leaf ][ leaf[y] ])
                {
                    turn _ = f[ cnt_leaf ][ leaf[y] ][t] ; 
                    ( dp[x][ _.to ] += _dp[ _.x ] * dp[y][ _.y ])%=p;
                }
                cnt_leaf = min( cnt_leaf + leaf[y] , 2*k); 
			
		
             }
    	}
    if(!bo)
    {
        dp[x][1] = dp[x][2] = 1;
        return ;
    }
    if(x!=1)
    {	
       
        memcpy(_dp,dp[x],sizeof(_dp));
        memset(dp[x],0,sizeof(dp[x]));
        re(t,1,_tot_f)
            ( dp[x][ _f[t].second ] += _dp[ _f[t].first ] )%=p ;
    }
    else
        re(t,1,tot)
        {
           ( ans += count(1,a[t],k+1) * dp[x][t] )%=p;
       }
}
int main()
{
	//freopen("0.in","r",stdin);
    _n = read(),k=read();
    re(i,2,_n)
        _a[read()][i] = 1;
    n = 1;
    build();
    re(i,1,n)
    	leaf[i] = min( leaf[i],2*k );
    if(n<=21)
    {
     solve1();  
	 return 0;
    }
    re(i,1,2*k)
    {
        node1.len = i;
        re(s,0,(1<<i)-1)
        {
            re(w,1,i)
                node1.s [w] = - ((s>>w-1)&1);
            node1.root = 0;
            dfs2(1,1);
            re(j,1,i)
                if(node1.s [j]!=-1)
                {
                    node1.root  = 1;
                    node1.s [j] = 1;
                    dfs2(1,1);
                    node1.root = 2;
                    re(k,j+1,i)
                        if(node1.s [k]!=-1)
                        {
                            node1.s[k] = 1;
                            dfs2(1,1);
                            node1.s[k] = 0;
                        }
                    node1.s[j]=0;
                }	
        }
    }			
    node1.clear();
    node1.root = 2;
    node1.len = k*2;
    a[++tot] = node1;
    mp[node1] = tot;
    re(i,1,tot)
        re(j,1,tot)
        {
            st1[0] = 0;
            Turn(a[i],a[j]);            
            if(st1[0])
      	      re(t,1,st1[0])
      	          f[ a[i].len ][ a[j].len ][ ++tot_f[a[i].len ][a[j].len ]] = turn(i,j,st1[t]);
       }
    re(i,1,tot)
    {
        int to = _Turn(i);
        if(to)
	    	_f[++_tot_f] = make_pair( i,to );
    }
    dfs4(1);
    printf("%lld\n",ans);
    return  0;
}

 

上一题