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
梦里如昨,此身似我非我
冷雾割风寒浸骨,意沉南柯