考试情况
前三题顺风顺水,除了没开long long挂了一发…
8分钟搞掉三题,状态非常好
第四题一眼看出来像是19年提高组T1格雷码,只是稍微加了一点处理
首先要求出总方案数,这个可以用组合数求解,由于满足题目要求的最大的组合数也不会爆long long,但如果阶乘加逆元去求解组合数,就一定会爆掉,所以选择用递推求出这个组合数
然后用二分思想搞一下,就搞定了,中途在左右端点上迷了一下,但后来还是成功绕回来了,45分钟搞掉了D题
然后就是每周的自闭日常…
题解
E
E题的关键在于一个巧妙地转化
比赛过程中思考到的最深处就是把每个深度的点存在vector里,然后再去找有哪些符合第一个约束条件,但当所有点都位于同一层,遍历就会复杂度爆炸
这时就需要用上这个转化,记录每个点开始被扫描的时间in,以及它的所有子树被扫描完的时间out
一个节点
y
y
y是另一个节点
x
x
x需要满足的约束条件为
i
n
y
≤
i
n
x
<
o
u
t
y
in_y\leq in_x < out_y
iny≤inx<outy
而对于同一深度的点,它的
i
n
in
in是单调递增的,故可以直接用lower_bound二分找出符合上述两个不等式的两端点,相减即为答案
值得一提的是,vector的lower_bound 用法与数组不同,具体写法见下文代码
#include<bits/stdc++.h>
using namespace std;
int tot=0;
const int N=2e5+10;
int in[N],out[N],dep[N];
vector<int> Dep[N];
vector<int> chi[N];
void dfs(int u)
{
in[u]=tot++;
Dep[dep[u]].push_back(in[u]);
for(int i=0;i<chi[u].size();i++)
{
dep[chi[u][i]]=dep[u]+1;
dfs(chi[u][i]);
}
out[u]=tot++;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<n;i++)
{
int p;
cin>>p;
chi[p].push_back(i+1);
}
dfs(1);
int q;
cin>>q;
for(int i=1;i<=q;i++)
{
int u,d;
cin>>u>>d;
cout<<(lower_bound(Dep[d].begin(),Dep[d].end(),out[u])-Dep[d].begin())-(lower_bound(Dep[d].begin(),Dep[d].end(),in[u])-Dep[d].begin())<<endl;
}
return 0;
}
总结
1.前几题A的越来越熟练,但还总是出现不开long long的错误,数据范围的观察并计算还需提升
2.学会了vector的lower_bound 用法
3.观察数据范围还是有用的,考试过程中想到了用二分去优化,但只是有这个念头,却根本不会实现