汕头市赛srm1X T3

给n<=100000个点的树,每个点有一个01串,长度m<=200,串的可以随时01取反,串的每一位对应权Vi,从根节点到某个节点经过决定哪些串取反后取得的最大价值为某个点的权值,求:在这棵树上乱走,不能走权相同的相邻两点,每个长度D的简单路径的方案数。

题目很奇怪。结论很不显然。TJM和HR大佬很强。

首先,最后遍历的树的深度不会超过logm。在树上每走一步,都可以把0的个数减少至少一半。

其次,未达到最大值的两个点权值肯定不同。道理同上。因此把目标转化为“在权值未满的树上走”,重点在如何找出这棵树。

再者,Mi表示属性i的选择情况,在n个串中,当且仅当所有的Mi取遍2^n种集合时没有最优方案,最优方案即所有属性都取得到。在这m个选择情况中若取遍2^n种集合,则有全为0的Mi,必须把它某一位对应的串取反,但这意味着那个“只有这一位为0的选择情况”不合法,我们要选另一位,这样一直搞下去,所有的串都取反了,那那些全为1的Mi就gg了。

最后,在n个串中,若Mi没取遍2^n种集合,一定可以构造出最优方案。方法即把不存在的某个选择情况的1的位取反。这时除非某个选择情况与不存在的那种完全相同,否则必然会有一位为1。

于是,两次dfs解决。第二次dfs的统计方案易错,注意一下。

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #include<algorithm>
 5 #include<math.h>
 6 //#include<iostream>
 7 using namespace std;
 8 
 9 int n,m;
10 #define maxn 100011
11 char s[233];bool mp[maxn][205];
12 struct Edge{int to,next;};
13 int vis[1050],state[205];
14 #define LL long long
15 LL dis[12][22],ans[22];
16 struct Tree
17 {
18     Edge edge[maxn<<1];
19     int first[maxn],le;
20     Tree() {le=2;}
21     void in(int x,int y)
22     {
23         edge[le].to=y;
24         edge[le].next=first[x];
25         first[x]=le++;
26     }
27     void dfsfirst(int x,int dep)
28     {
29         int tot=(1<<dep);
30         for (int i=1;i<=m;i++)
31         {
32             if (mp[x][i]) state[i]|=1<<(dep-1);
33             if (vis[state[i]]!=x) tot--,vis[state[i]]=x;
34         }
35         if (tot) first[x]=0;
36         for (int i=first[x];i;i=edge[i].next)
37             dfsfirst(edge[i].to,dep+1);
38         for (int i=1;i<=m;i++)
39             if (mp[x][i]) state[i]^=1<<(dep-1);
40     }
41     void dfsfirst()
42     {
43         memset(vis,0,sizeof(vis));
44         dfsfirst(1,1);
45     }
46     void dfssec(int x,int dep)
47     {
48         memset(dis[dep],0,sizeof(dis[dep]));
49         dis[dep][0]=dis[dep][1]=1;
50         for (int i=first[x];i;i=edge[i].next)
51         {
52             dfssec(edge[i].to,dep+1);
53             for (int j=dep+1;j<=10;j++)
54                 for (int k=dep+1;k<=10;k++)
55                     ans[j+k-dep-dep]+=dis[dep][j-dep]*dis[dep+1][k-dep];
56             for (int j=1;j<=20-dep-dep;j++) dis[dep][j+1]+=dis[dep+1][j];
57         }
58     }
59     void dfssec() {dfssec(1,1);}
60 }t;
61 int x;
62 int main()
63 {
64     scanf("%d%d",&n,&m);
65     for (int i=1;i<=n;i++)
66     {
67         scanf("%s",s);
68         for (int j=0;j<m;j++) mp[i][j+1]=s[j]-'0';
69     }
70     for (int i=1;i<=m;i++) scanf("%d",&x);
71     for (int i=2;i<=n;i++) scanf("%d",&x),t.in(x,i);
72     t.dfsfirst();
73     memset(ans,0,sizeof(ans));
74     t.dfssec();
75     int i;
76     for (i=20;i>=1;i--) if (ans[i]) break;
77     printf("%d ",n);
78     for (int j=2;j<=i;j++) printf("%lld ",ans[j]);
79     return 0;
80 }
View Code

 

posted @ 2017-08-13 10:35  Blue233333  阅读(125)  评论(0编辑  收藏  举报