zoukankan      html  css  js  c++  java
  • [atAGC050F]NAND Tree

    当$n$为偶数,暴力$o(n)$枚举第一次操作,以下只考虑$n$为奇数的情况

    此时,$n-1$即操作次数为偶数,找到最小的$i$(其中$1le ile frac{n-1}{2}$),满足第$2i-1$和第$2i$次操作交换后不影响答案,并将其与交换后的操作相互抵消(答案对2取模)

    考虑两个操作相互影响,显然需要有公共点,不妨假设两边分别为$(x,y)$和$(y,z)$,两种操作顺序的结果分别为$((c_{y}and c_{x})oplus 1)and c_{z})oplus 1$和$((c_{y}and c_{z})oplus 1)and c_{x})oplus 1$

    首先当$c_{z}=c_{z}$时结果显然相同,因此有$c_{x} e c_{z}$,分类讨论后可以发现,不论$c_{y}$是0或1,只要$c_{x} e c_{z}$,这两个式子结果必然不同(即分别为0和1)

    根据这个规律,每一次操作可以看作合并一条长为3的链$x-y-z$(要求$c_{x} e c_{z}$)以及其边集,且可以任意选择合并后的点的权值(即对于每一条链还可以产生两种方案)

    考虑将这个方案记录在点上,即将所有点分为三类:1.点权为0;2.点权为1;3.点权任意(称此类点为特殊点),接下来考虑特殊点参与合并的情况:

    1.特殊点作为$y$,此时其权值并没有意义,0和1两种方案相互抵消,即可以强制其不能作为$y$

    2.$x$和$z$中恰有一个特殊点,此时特殊点必须选择与另一个非特殊点不同的权值,合并后也是一个特殊点

    3.$x$和$z$都是特殊点,此时$x$选0和$z$选1以及$x$选1和$z$选0两种方案相互抵消,即可强制$x$和$z$不能同时为特殊点

    利用这些信息,我们可以对问题用另外一种方式描述——

    执行以下操作$frac{n-1}{2}$次,操作为:

    选择树上一条长度为3的链$x-y-z$,要求:1.$y$不为特殊点;2.$x$和$z$不同时为特殊点;3.若$x$和$z$都不为特殊点,则$c_{x} e c_{z}$

    将这条链上的点合并,并令合并的点作为特殊点

    求合并方案数,答案对2取模

    同时注意到,在这样的强制下,特殊点数量单调不减,因此一旦出现两个特殊点,就无法再消除了,因此必然是初始产生一个特殊点,之后每一次操作的链都包含其

    枚举第一次操作中$c_{x}$和$c_{z}$中为1的点,以其为根建树,此时问题又可以看作——

    将每条边看作从父亲到儿子的有向边,对该DAG进行拓扑排序,求有多少种拓扑排序的结果$a_{i}$,满足:$c_{a_{3}}=0$且$forall 1le ile frac{n-1}{2}$,$a_{2i}$是$a_{2i+1}$的父亲,答案对2取模

    事实上,这两个条件都可以忽略,我们分别来说明:

    1.$c_{a_{3}}=0$,对于$c_{a_{3}}=1$的情况,其恰好会在$a_{3}$时考虑到,且将这条链翻转并不影响其余点的拓扑排序的情况(可以从树的角度看,也可以从方案的角度看)

    2.要求$a_{2i}$是$a_{2i+1}$的父亲,注意到若相邻两点不为父子关系,交换后一定不影响拓扑性,因此只需要找到最小的$i$满足$a_{2i}$不是$a_{2i+1}$的父亲,将两者交换相互抵消即可

    综上,问题就变为拓扑排序数,即$frac{n!}{prod_{i=1}^{n}sz_{i}}$(其中$sz_{i}$为其子树大小),统计2的次数即可

    总复杂度为$o(n^{3})$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 305
     4 #define fi first
     5 #define se second
     6 struct Edge{
     7     int nex,to;
     8 }edge[N<<1];
     9 pair<int,int>e[N];
    10 int E,n,ans,two[N],head[N],c[N],sz[N];
    11 void add(int x,int y){
    12     edge[E].nex=head[x];
    13     edge[E].to=y;
    14     head[x]=E++;
    15 }
    16 void dfs(int k,int fa){
    17     sz[k]=1;
    18     for(int i=head[k];i!=-1;i=edge[i].nex)
    19         if (edge[i].to!=fa){
    20             dfs(edge[i].to,k);
    21             sz[k]+=sz[edge[i].to];
    22         }
    23 }
    24 int calc(int k){
    25     int ans=0;
    26     for(int i=1;i<=n;i++)
    27         if ((i!=k)&&(c[i])){
    28             dfs(i,0);
    29             int tot=0;
    30             for(int j=1;j<=n-(k>0);j++)tot+=two[j];
    31             for(int j=1;j<=n;j++)
    32                 if (j!=k)tot-=two[sz[j]];
    33             if (!tot)ans^=1;
    34         }
    35     return ans;
    36 }
    37 int main(){
    38     scanf("%d",&n);
    39     for(int i=1;i<n;i++)scanf("%d%d",&e[i].fi,&e[i].se);
    40     for(int i=1;i<=n;i++)scanf("%d",&c[i]);
    41     for(int i=1;i<=n;i++)
    42         if (i&1)two[i]=0;
    43         else two[i]=two[i>>1]+1;
    44     if (n&1){
    45         memset(head,-1,sizeof(head));
    46         for(int i=1;i<n;i++){
    47             add(e[i].fi,e[i].se);
    48             add(e[i].se,e[i].fi);
    49         }
    50         ans=calc(0);
    51     }
    52     else{
    53         for(int i=1;i<n;i++){
    54             E=0;
    55             memset(head,-1,sizeof(head));
    56             int p=c[e[i].fi];
    57             c[e[i].fi]=((c[e[i].fi]&c[e[i].se])^1);
    58             for(int j=1;j<n;j++){
    59                 if (j==i)continue;
    60                 int x=e[j].fi,y=e[j].se;
    61                 if (x==e[i].se)x=e[i].fi;
    62                 if (y==e[i].se)y=e[i].fi;
    63                 add(x,y);
    64                 add(y,x);
    65             }
    66             ans^=calc(e[i].second);
    67             c[e[i].fi]=p;
    68         }
    69     }
    70     printf("%d",ans);
    71 } 
    View Code
  • 相关阅读:
    ASP.NET Web API是如何根据请求选择Action的?[上篇]
    Ruby的对象模型
    MongoDB学习3
    Linux目录树详细说明
    Matlab.NET混合编程技巧之——直接调用Matlab内置函数(附源码)
    [置顶] SQL注入安全分析
    3.9 聚集和联接
    Qt之QTemporaryFile(文件名唯一,且可以自动删除)
    调用Windows属性窗口(居然是通过注册表来调用的)
    QTextEdit中选中文本修改字体与颜色,全部文本修改字体与颜色(设置调色板的前景色、背景色、文字颜色以及基色)
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14620533.html
Copyright © 2011-2022 走看看