汕头市赛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 }

时间: 2024-07-31 18:11:20

汕头市赛srm1X T3的相关文章

汕头市队赛 SRM13 T3

这道题可以贪心 维护一个答案队列 枚举位置 每次将比当前位置大的队尾全部替代掉 记录删了多少了就好了 #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<string> #define LL long long using namespace std; const int M=1e7+7; int n,k,cnt; char s[M]

汕头市队赛 SRM1X T2 ——扫描线

绵津见-终 SRM 13 背景 "西瓜也是可以种在海上的!"--绵津见 然而种在海上的西瓜最需要防范的,是时不时会涌向瓜田的阵阵海浪. 幸好,身为海神的绵津见可以释放魔法"水平如镜"来阻止海浪拍打西瓜. 然而,当西瓜一个接一个成熟之时,它们就要离开瓜田,飘向遥远的彼岸.绵津见的魔法无法保护离开瓜田的西瓜们,但至少,也得知道西瓜们遭遇了多大的风浪啊. 描述 我们用一个坐标系来描述大海,绵津见的瓜田位于x轴下方,每当有一个西瓜成熟时,它会从x轴上一点出发,沿一条平行y轴

汕头市队赛SRM14 T3覆盖

我们可以考虑两种情况 区间之间不相重叠 和 重叠 f[i][j]表示以当前最后一个区间以 i 结尾 并且选了 j 个区间 不相重叠的话 只要选 1-i-w 的max再加上 包含i在内的前四个数的和 相交的话 考虑因为可选的区间长度是固定的 所以我们可以考虑单调队列优化 sum维护的是前缀和 f[i][j]=f[k][j-1]+sum[i]-sum[k] 这样因为sum[i]是固定的 所以我们队列里维护的是f[k][j-1]-sum[k]就好辣 #include<cstdio> #include

汕头市队赛 SRM10 T3 数学上来先打表

数学上来先打表 SRM 10 描述 给出 n个点(不同点之间有区别),求出满足下列条件的连边(双向边)方案:1.每条边连接两个不同的点,每两个点之间至多有一条边2.不存在三个点a,b,c使三个点间两两可以互相到达且两两之间最短距离相等3.边的长度均为1 输入格式 一行,一个整数n 输出格式 一行,一个整数,表示方案数对1004535809取模的结果. 样例输入 3 样例输出 7 数据范围与约定 对于8组数据,1<=n<=9对于余下8组数据,10<=n<=2000 样例解释 三个点之

汕头市赛srm10 T2

n个数,分组,数Ai要在至少含有Ai个数的组,求最多分多少组. 方法一:大的数应该尽量跟大的在一起,这样才能让小的出现很多很多组,所以从大到小排序,给当前序列中最大的数x分x个数.代码如下: 1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<algorithm> 5 //#include<iostream> 6 using namespace std;

January 24th 模拟赛A T3【NOI2014模拟】数列 Solution

题目空降 Description 给定一个长度为\(n\)的正整数数列\(a_i\). 定义两个位置的\(f\)为两者位置差与数值差的和,即\(f_{x,y}=|x-y|+|a_x-a_y|\). 你需要写一个程序支持两种操作(\(k\)都是正整数): Modify x k:将第\(x\)个数的值修改为\(k\). Query x k:询问有几个\(i\)满足\(f_{x,i}\leq k\). 询问不仅要考虑当前数列,还要考虑任意历史版本,即统计任意位置上出现过的任意数值与当前的\(a_x\)

【7.24校内交流赛】T3【qbxt】复读警告

数据范围:N,key<=1000; 首先看题目背景,显然不是DP就是图论,但是这显然不是个图论,因此这就是个DP: 接下来考虑怎么DP 我们定义dp[i][j]表示现在dp到了第i个数,当前i个数%key=j的方案数: 最后答案就是dp[n][0]: 考虑转移: 当我们希望求出前i个数中的某几个数相加%key=j的方案数时,我们有两种选择: 1.选择第i个数,那么我们先要求出选第i个数之前%key=?: int t=j-a[i]%key; if(t<0) t+=key; 然后dp[i][j]+

竞赛图如何构造三元环

讲解视频 一场NOIp模拟赛的T3里看到的一个东西,因为那道题目不开放评测,所以简单写一下. 假设存在这样一张竞赛图,其中存在这样一个环 $node_a \rightarrow node_b \rightarrow node_c \rightarrow node_d \rightarrow node_e \rightarrow node_a$ 首先明确,这是一个竞赛图,对于任意的$node_a$和$node_b$,要么存在$node_a \rightarrow node_b$要么存在$node_

暑假集训D11总结

%dalao 今天某学长来讲一个极其高深的数据结构——线段树(woc哪里高深了),然而并没有时间整理笔记= =,所以明天在扔笔记咯= = 考试 今天考试,一看数据范围,woc暴力分给的真足,然后高高兴兴地打了三个暴力,自己估的还可以,然后就开始乱搞写一些高深的东西,比如说简单的计时器,好难的SpalySplay,然后,,,然后发现自己都没理解题 在欢声笑语中打出GG 题解: T1 [NOIP 2011]聪明的质监员 T2 [Tyvj模拟赛]运 T3 NOI2011 兔农(别问我为啥没链接,都是泪