1006

A

打表+线性筛求质数的时候维护劳伦斯数+前缀和优化
原理同质数筛的原理:\(i \times prime[j]\)只会出现一次,保证了\(O(N)\)的复杂度
我又双叒叕没想到
黄学长的博客如下

for(int i=2;i<=1e7;i++)
    {
        if(!book[i]){prime[++cnt]=i;mark[i]=true;}
        for(int j=1;j<=cnt&&1ll*prime[j]*i<=1e7;j++)
        {
            book[i*prime[j]]=true;
            if(!book[i])mark[i*prime[j]]=true;
            if(i%prime[j]==0)break;
        }
    }
	 for(int i=2;i<=1e7;i++)sum[i]=sum[i-1]+mark[i];

B

dijikstra+状压(K<=10)
设 dis[i][s] 表示到i号点时,手中的通行卡的集合为s的最短距离
讨论每个点的边时,需要if((need[i]&x.s)==need[i])判断这条边是否能通行,再讨论是否能更新这条边所连点的dis值

然而\(50%\)\(K=0\)的分我都没拿到,起因是

dijkstra

首先,dijikstra的重载运算符这样写

struct iakioi{
	int id;
	int dis;
	bool operator <(const iakioi &a)const{
		return dis>a.dis;
	}
}tmp;

看清楚了,重载都是>号不是<号,否则priority_queue将会从大到小排列

而且,dis写在a.dis前面

其次

while (!Q.empty()){
	int u = Q.top().Num;
	Q.pop();
	if (mark[u]) continue;
	mark[u] = true;
	for (int i=Last[u]; i!=0; i=Next[i]){
		int v = End[i];
		if (!mark[v] && dis[v] > dis[u] + Len[i]){
			dis[v] = dis[u] + Len[i];
			tmp.Num = v; tmp.dis = dis[v];
			Q.push(tmp);
		}
	}
}

这个写法是错误的
具体错误在这里

res(i,x){
	int v = End[i];
	//////////////////////////////////////////
	if (!mark[v] && dis[v] > dis[u] + Len[i]){
	//////////////////////////////////////////
		dis[v] = dis[u] + Len[i];
		tmp.Num = v; tmp.dis = dis[v];
		Q.push(tmp);
	}
}

其实这个v点有没有在堆里都是可以的QwQ(Mark[v]=1也没有关系)
也就是说这个写法应该是

res(i,x){
	int v = End[i];
	//////////////////////////////////////////
	if (dis[v] > dis[u] + Len[i]){
	//////////////////////////////////////////
		dis[v] = dis[u] + Len[i];
		tmp.Num = v; tmp.dis = dis[v];
		Q.push(tmp);
	}
}

C

把三个点两两求LCA ,取其中深度最大的LCA,答案就是dis(LCA,z)

结论

对于树上的三个点,两两取LCA,得到的三个LCA中一定有两个是相同的,且这两个LCA的深度比另一个要小。而另一个LCA是树上唯一一个到这三个点的路径没有边重叠的点。

证明在此Phenning的blog

posted @ 2019-10-08 19:54  羽错光阴  阅读(372)  评论(0编辑  收藏  举报