10.4 考试总结
\(\large 10.4 考试总结\)
得分情况
| T1估分 | T1实分 | T2估分 | T2实分 | T3估分 | T3实分 | T4估分 | T4实分 | 总估分 | 总实分 |
|---|---|---|---|---|---|---|---|---|---|
| 40 | 100 | 10 | 11 | 40 | 40 | 20 | 8 | 110 | 159 |
时间分配
计划:
T1(1hour)+T2(1hour)+T3(0.5hour)+T4(1hour)+所有代码检查(0.5hour)
实施:
基本一致,T2完全没有思路基本没用什么时间
核心问题与改进计划
问题:
T2没有一点思路,知识点短板明显,数据结构掌握不牢
计划:
查漏补缺,按照计划上写的去练习bbcoj上的题目,巩固知识点,加强代码能力
题目分析
\(\textup{\textbf{{\color{black}兄弟们(brother)}}}\)
思路
考场上打的是不严格\(O(nmlog_n)\),即暴力+倍增,应该是40分代码,结果AC了。
正解是用DFS序记录每一棵子树对应的编号区间。再将节点按照高度分类,高度相同的放到同一个vector。
求k级祖先时,用倍增。这样我们可以在 \(O(log_n)\)里求出祖先,然后获得祖先对应子树的编号区间,二分查找即可。
时间复杂度严格\(O(mlog_n)\)
考场code:
#include<bits/stdc++.h>
using namespace std;
inline int read() {
int s=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
return s*f;
}
const int N=1e5+5;
int n,m;
int ver[N<<1],head[N],ne[N<<1],tot;
vector<int> v[N];
int vis[N],q[N],fa[N],scc[N],sz[N],dep[N],f[N][30];
int cnt,ans;
void add(int x,int y){
ver[++tot]=y,ne[tot]=head[x],head[x]=tot;
}
void dfs(int x,int fat,int topp){
// fa[x]=fat;
f[x][0]=fat;
for(int i=1;i<=18;i++)
f[x][i]=f[f[x][i-1]][i-1];
scc[x]=topp;
dep[x]=dep[fat]+1;
// cout<<x<<' '<<dep[x]<<'\n';
for(int i=head[x];i;i=ne[i]){
int y=ver[i];
if(vis[y]) continue;
vis[y]=1;
dfs(y,x,topp);
}
}
int nk(int x,int k){
for(int i=18;i>=0;i--)
if((1<<i)<=k) k-=(1<<i),x=f[x][i];
return x;
}
bool find(int x,int g){
for(int i=18;i>=0;i--)
if(dep[f[x][i]]>=dep[g]) x=f[x][i];
if(x==g) return 1;
return 0;
//暴力
// if(dep[x]<dep[g]) return 0;
// if(fa[x]==0) return 0;
// if(fa[x]==g) return 1;
// return find(fa[x],g);
}
int main(){
freopen("brother.in","r",stdin);
freopen("brother.out","w",stdout);
n=read();
for(int i=1;i<=n;i++){
int x=read();
if(x!=0) add(x,i);
else q[i]=1;
}
for(int i=1;i<=n;i++) if(q[i]) dfs(i,0,++cnt);
for(int i=1;i<=n;i++) v[dep[i]].push_back(i);
dep[0]=-1;
m=read();
while(m--){
int x=read(),k=read();
if(k>dep[x]-1){
printf("0\n");
continue;
}
int p=nk(x,k);
// cout<<p<<'\n';
ans=0;
// cout<<find(x,p)<<'\n';
for(int i=0;i<v[dep[x]].size();i++){
int y=v[dep[x]][i];
int q=find(y,p);
if(scc[y]==scc[x] && q==1) ans++;
// cout<<y<<' ';
}
// cout<<'\n';
printf("%d\n",ans-1);
}
return 0;
}
\(\textup{\textbf{{\color{black}Vifact与猫猫(cat)}}}\)
思路
考场思路:
多想一会儿就应该知道这是道线段树分治。但是我肯定是不可能调出来的,所以果断骗分。
正解思路:
如果只考虑\(d_i\),那么i作为右端点,可行的左端点的选择区间是单调增的,记为\(g_i\)可以用线段树在 \(O(nlog_n)\)内求出。
考虑分治,当前区间[l,r]中\(c_i\)的最大值作为分治中点mid。
考虑\(d_i\)的限制,每次\(g_i\)>当前左端点时,用线段树更新答案。
code:
\(\textup{\textbf{{\color{black}数论计算(count)}}}\)
思路
考场思路
一眼完全背包(40pts),感觉有问题,换成DFS暴力搜索(依旧40pts)。没什么太大区别。
正解思路
与\(\color{black}{这道题}\) 十分相似
同余最短路
code:
\(\textup{\textbf{{\color{black}黑白图(dye)}}}\)
思路
二分图染色
code:
本文来自博客园,作者:{昕木},转载请注明原文链接:https://www.cnblogs.com/Austin0928/articles/19125707

浙公网安备 33010602011771号