Codeforces Round #316 (Div. 2) D、E

Problem D:

题意:给定一棵n个点树,每个点有一个字母,有m个询问,每次询问某个节点x的子树中所有深度为k的点能否组成一个回文串

分析:一堆点能组成回文串当且仅当数量为奇数的字母不多于1个,显然这个状态可以用二进制表示

那么对于单个询问如何快速找到所有符合要求的点呢?

这里可以考虑树的dfs序,我们把深度相同的点按照dfs序加入集合中,易知在同一颗子树中的点肯定形成了一个连续的区间。

因此每次可以通过二分子树根节点的进入dfs序的时间和出dfs序的时间来找到这个区间

找到区间后可以根据预处理出的异或前缀和直接得到这个区间的二进制状态,再check一下即可

复杂度 n+m*(logn+26)

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 vector<int>g[500010];
 4 int a[500010];
 5 char s[500010];
 6 int in[500010];
 7 int out[500010];
 8 int n,m;
 9 int t=0;
10 struct node
11 {
12     int t,val;
13     bool operator <(const node &a)const
14     {
15         return t<a.t;
16     }
17 };
18 vector<node>ans[500010];
19 void dfs(int now,int d)
20 {
21     in[now]=++t;
22     ans[d].push_back(node{t,ans[d][ans[d].size()-1].val^a[now]});
23     for(int i=0;i<(int)g[now].size();i++)
24     {
25         int to=g[now][i];
26         dfs(to,d+1);
27     }
28     out[now]=++t;
29 }
30 int main()
31 {
32     scanf("%d%d",&n,&m);
33
34
35     for(int i=2;i<=n;i++)
36     {
37         int x;
38         scanf("%d",&x);
39         g[x].push_back(i);
40     }
41
42     scanf("%s",s);
43     for(int i=1;i<=n;i++)
44     {
45         a[i]=1<<(s[i-1]-‘a‘);
46         ans[i].push_back(node{0,0});
47     }
48     dfs(1,1);
49     while(m--)
50     {
51         int p,x;
52         scanf("%d%d",&p,&x);
53         auto l=lower_bound(ans[x].begin(),ans[x].end(),node{in[p],0});
54         auto r=upper_bound(ans[x].begin(),ans[x].end(),node{out[p],0});
55         l--;
56         r--;
57         int st=((*l).val)^((*r).val);
58         int cnt=0;
59         for(int i=0;i<26;i++)
60         {
61             if(st&(1<<i))
62                 cnt++;
63         }
64         if(cnt>1)
65         {
66             puts("No");
67         }
68         else
69         {
70             puts("Yes");
71         }
72     }
73     return 0;
74 }

Problem E:

题意:给一个n*m的棋盘,每个格子有一个字母,现在从1,1走到n,m,每次只能向右或者向下走,问走的路径上形成的字符串是回文串的方案书是多少

分析:从回文串的中点,即x+y=(n+m)/2的地方开始dp ,dp[i][j][k]存储当前回文长度为2*i ,左端点的x为i,右端点的x为j的回文串有多少个。

然后按照对角线递推即可。转移时注意必须满足左端点的x必须小于右端点,y必须大于右端点

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int n,m;
 4 int dp[2][505][505];
 5 char s[505][505];
 6 const int mod=1e9+7;
 7 int main()
 8 {
 9     scanf("%d%d",&n,&m);
10     for(int i=0; i<n; i++)
11     {
12         scanf("%s",s[i]);
13     }
14     int ok=1;
15     for(int i=(n+m)/2-1; i>=0; i--)
16     {
17         memset(dp[i%2],0,sizeof(dp[i%2]));
18         int j=n+m-2-i;
19         for(int x1=0; x1<n; x1++)
20         {
21             int y1=i-x1;
22             if(y1<0||y1>=m)
23                 continue;
24             for(int x2=0; x2<n; x2++)
25             {
26
27                 int y2=j-x2;
28                 if(y2<0||y2>=m)
29                     continue;
30                 if(x1>x2||y1>y2)
31                     continue;
32                 if(s[x1][y1]==s[x2][y2])
33                 {
34                     if(ok==1)
35                     {
36                         dp[i%2][x1][x2]=1;
37                         continue;
38                     }
39                     for(int a=0; a<2; a++)
40                     {
41                         if(x1+a>=n)
42                             continue;
43                         for(int b=-1; b<1; b++)
44                         {
45                             if(x2+b<0)
46                                 continue;
47                             dp[i%2][x1][x2]=(dp[i%2][x1][x2]+dp[(i+1)%2][x1+a][x2+b])%mod;;
48                         }
49                     }
50                 }
51             }
52         }
53         ok++;
54     }
55     printf("%d\n",dp[0][0][n-1]);
56     return 0;
57 }

时间: 2024-10-11 04:53:32

Codeforces Round #316 (Div. 2) D、E的相关文章

Codeforces Round #250 (Div. 2) C、The Child and Toy

注意此题,每一个部分都有一个能量值v[i],他移除第i部分所需的能量是v[f[1]]+v[f[2]]+...+v[f[k]],其中f[1],f[2],...,f[k]是与i直接相连(且还未被移除)的部分的编号. 注意题目移除的都是与第i部分直接相连的部分的能量值, 将本题目简化得,只考虑两个点1和2,1和2相连,1的能量值是10,2的能量值是20, 移除绳子时,要保持能量最小,可以移除部分2,这样移除的能量就是与2相连的部分1的能量即是10: 故每次相连两部分都移除能量值大的即可 #includ

Codeforces Round #251 (Div. 2) C、D

Codeforces Round #251 (Div. 2) C题: 题意:给定一些数字,要把这些数字方程k行,其中p行和为奇数,剩下和为偶数. 思路:根据奇数偶数的性质,先把p行放1个奇数,然后看看剩下的奇数是不是偶数个,如果不是肯定不满足,然后判断一下剩下的奇数个数/2加上偶数个数是否多余p个,如果不是肯定不满足,然后把这些放入p行,还有剩下的数字就全丢到最后一行去. D题: 题意:给定两个序列,每次操作可以对序列中的数字进行+1或者-1,要使得a序列的最小大于b序列的最大,问最少需要几次操

Codeforces Round #298 (Div. 2) A、B、C题

题目链接:Codeforces Round #298 (Div. 2) A. Exam An exam for n students will take place in a long and narrow room, so the students will sit in a line in some order. The teacher suspects that students with adjacent numbers (i and i + 1) always studied side

Codeforces Round #316 (Div. 2) B. Simple Game

思路:把n分成[1,n/2],[n/2+1,n],假设m在左区间.a=m+1,假设m在右区间,a=m-1.可是我居然忘了处理1,1这个特殊数据.被人hack了. 总结:下次一定要注意了,提交前一定要看下边界数据,不要急着交. 题目链接:http://codeforces.com/problemset/problem/570/B <pre name="code" class="cpp">#include<bits/stdc++.h> using

Codeforces Round #316 (Div. 2) C. Replacement

题意:给定一个字符串,里面有各种小写字母和' . ' ,无论是什么字母,都是一样的,假设遇到' . . ' ,就要合并成一个' .',有m个询问,每次都在字符串某个位置上将原来的字符改成题目给的字符,问每次须要多少次合并次数.才使字符串没有' .. ' 思路:最原始的想法,就是对于每一次询问,都遍历整个字符串.这样时间复杂度o(n*m),就高达10^10方,非常明显会tle. 换下思路,事实上每次询问所改变的字符都会保留到下一次.也就是下一次的次数就会受到上一次的影响,那么我仅仅要就算出第一次的

Codeforces Round #604 (Div. 2) D、E、F题解

Beautiful Sequence \[ Time Limit: 1000 ms\quad Memory Limit: 256 MB \] 首先我们可以考虑到 \(0\) 只能 和 \(1\) 放在一起.\(3\) 只能和 \(2\) 放在一起,那么我们想办法先把 \(0\) 和 \(3\) 凑出来,最后就剩下 \(1\) 和 \(2\) 了,我们只要把他们放在一起就可以了. 所以我们可以贪心考虑三个 \(string\),分别长成 \(0101...0101\).\(2323...2323\

Codeforces Round #316 (Div. 2) D计算在一棵子树内某高度的节点

题:https://codeforces.com/contest/570/problem/D 题意:给定一个以11为根的n个节点的树,每个点上有一个字母(a~z),每个点的深度定义为该节点到11号节点路径上的点数.每次询问a,ba,b查询以aa为根的子树内深度为bb的节点上的字母重新排列之后是否能构成回文串.分析:很明显是个树上启发式合并.显然,只要深度为bb结点的所有颜色中,至多有一种的数量为奇数就可以构成回文串了. #include<bits/stdc++.h> using namespa

Codeforces Round #316 (Div. 2) A

Description The country of Byalechinsk is running elections involving n candidates. The country consists of m cities. We know how many people in each city voted for each candidate. The electoral system in the country is pretty unusual. At the first s

Codeforces Round #316 (Div. 2) D Tree Requests

官方题解是离线询问,dfs树形转线性,然后二分找区间. 还有一种比较好的做法是直接dfs,将当前访问这个结点u相关的询问之前的状态存起来,然后访问完以后利用异或开关性,得到这颗子树上的答案. 代码是学习别人的http://blog.csdn.net/squee_spoon/article/details/47666667 当时做的时候想得是树形转线性,觉得dfs会暴栈,想用bfs,之前又没写过,于是愣了一个钟头. #include<bits/stdc++.h> using namespace