1006
Posted oieredsion
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1006相关的知识,希望对你有一定的参考价值。
hh A题算了下空间感觉没问题 没想到开了4个数组 成功bao 0
期望290 实际 175
naiive
A.劳伦斯数
数学家劳伦斯定义: 对于任意整数 x, 如果 x 是素数, 或者 x 可以表示成两个素数的乘积, 那
么 x 就称为劳伦斯数。
现在给出 Q 个询问, 每个询问形如“L R” , 需要你快速统计出区间[L,R]中有多少个劳伦斯
数。
解:
这题肯定和线性筛有关系
然后打了一波板子后 发现 对于x 表示成两个素数的乘积的形式 我们可以这样想想
当i是一个质数 那么i*pri[j] 就会满足条件 并且由于线性筛的特性 pri[j] 一定是一个最小的质因数
就像这样
if(phi[le]==i)
p[i*phi[j]]=1;
或者定义pr[x] 表示x 的最小质因数
那么充要条件为 pr[i/pr[i]]=i/pr[i]; 即最小的质因数是自己就满足素数的条件
考完后我发现自己还是太naiive
看到可能int 溢出不知道强制类型转换 省掉空间
看到标记的数组还开long long
1e9+1 搞定的事情 自己非要数着写
B.逃离迷宫
文件名: escape.cpp
输入输出名: escape.in/escape.out
时空限制 1s, 256m
题目描述
队员们在玩一款迷宫游戏。 在一个山体迷宫中, 共有 N 个山洞, 编号 1 到 N。
游戏开始时, 队员们位于 1 号山洞, 出口在 N 号山洞。 每个山洞里面可能有一些通行卡, 进入
一个山洞, 队员们就能获得该山洞的通行卡。 通行卡有 K 种, 编号 1 到 K。 山洞之间存在单向道路,
每条道路都需要拥有指定编号的通行卡才能通过。
通过一条道路的时间是 1 分钟, 队员们想知道, 最少多少分钟, 就能走到出口。
输入格式:
第一行, 三个整数 N,M,K, 表示山洞数、 道路数和通行卡种数
接下来 K 行, 其中第 i 行描述 i 号山洞存在的通行卡的情况, 用 N 个空格间隔的 0 或 1 来表
示。 若其中第 j 个数为 1, 表示该山洞存在 j 号通行卡, 为 0 则表示不存在第 j 号通行卡。
接下来 M 行, 每行描述一条道路的情况。 首先是两个数 X 和 Y, 表示有一条从 X 出发到达 Y
的通道。 接下来 K 空格间隔的个 0 或 1, 表示通过该通道需要拥有的通行卡的情况, 若其中第 j 个
数为 1, 表示需要 j 号通行卡, 为 0 则表示不需要。
输出格式:
一个整数, 表示最少所需时间。 若无法到达出口, 输出“No Solution” 。
样例输入:
3 3 2
1 0
0 1
0 0
1 3 1 1
1 2 1 0
2 3 1 1
样例输出:
2
解:
多维最短路+状压DP
定义f[i][j] 表示 在i 号点 集合为j 所需要的最小时间
满足条件: $ ((r.s$ & $ le[i])==le[i])$
转移为: $
if(dis[r.f][r.s]+1<dis[u][(r.s)|w[u]])
dis[u][(r.s)|w[u]]=dis[r.f][r.s]+1,
if(!mark[u][(r.s)|w[u]])
mark[u][(r.s)|w[u]]=1;
$
代码:
//
#include<bits/stdc++.h>
using namespace std;
#define maxnn 6010
int mark[maxnn][1<<11];
int n,m,k;
int all=0;
int las[maxnn],en[maxnn],le[maxnn],tot,nex[maxnn];
int dis[maxnn][1<<11];
int w[maxnn];
typedef pair<int ,int > P;
#define f first
#define s second
#define inf 100000000
void add(int a ,int b,int c)
en[++tot]=b;
nex[tot]=las[a];
las[a]=tot;
le[tot]=c;
void spfa()
queue<P> Q;
for(int i=1;i<=n;i++)
for(int j=0;j<=all;j++)
dis[i][j]=inf;
mark[i][j]=0;
dis[1][w[1]]=0;
mark[1][w[1]]=1;
Q.push(make_pair(1,w[1]));
while(Q.size())
P r=Q.front();
Q.pop();
mark[r.f][r.s]=0;
for(int i=las[r.f];i;i=nex[i])
int u=en[i];
if(!((r.s&le[i])==le[i]))continue;
if(dis[r.f][r.s]+1<dis[u][(r.s)|w[u]])
dis[u][(r.s)|w[u]]=dis[r.f][r.s]+1;
if(!mark[u][(r.s)|w[u]])
mark[u][(r.s)|w[u]]=1;
Q.push(make_pair(u,(r.s)|w[u]));
void FIE()
freopen("escape.in","r" ,stdin);
freopen("escape.out","w",stdout);
int main()
//FIE();
int x,y,z;
scanf("%d%d%d",&n,&m,&k);
all=(1<<k)-1;
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++)
scanf("%d",&z);
if(z==1)
w[i]=w[i]|((1<<j-1));
for(int i=1;i<=m;i++)
scanf("%d%d",&x,&y);
int tmp=0;
for(int j=1;j<=k;j++)
cin>>z;
if(z==1)
tmp=tmp|((1<<j-1));
add(x,y,tmp);
spfa();
int ans=100000000;
for(int i=0;i<=all;i++)
ans=min(ans,dis[n][i]);
if(ans==100000000)
puts("No Solution");
else
printf("%d",ans);
C 线路重叠
某城市有非常发达的公共交通系统。 有 N 个公交站, 通过 N-1 条双向道路连接起来。 公交站编
号 1 到 N, 任意两个公交站都可以相互到达。
队员们提出 Q 个询问, 每个询问形如“X Z Y” , 表示问从 X 到 Z 的公交线路, 与从 Y 到 Z 的
公线路, 存在多少个重叠的车站。 重叠指车站既在 X 到 Z 路线中, 也在 Y 到 Z 路线中。
输入格式:
第一行, 两个整数 N 和 Q, 表示询问数
接下来 N-1 行, 每行两个整数 X 和 Y, 表示编号 X 和 Y 的公交站存在道路相连。
接下来 Q 行, 每行三个整数 X,Z,Y, 表示一次询问
输出格式:
Q 行, 每行一个整数, 对应一次询问的答案
样例输入:
3 3
1 2
2 3
1 2 3
1 1 3
3 1 3
样例输出:
1 1 3
解:
考场上没有注意到这是一个固定终点的问题 敲了一发树剖 T 75 旁边的某位ruan姓jul 打的比我复杂T90 我... 充分证明了fread 的重要性 时间复杂度\\(O(Q \\times (log2(n))^2)\\)
考试后 利用树状数组优化 还是T90...
树剖的想法很好想
对于一段距离 在这条路径上+1 对于另一段距离 在他的路径上查询区间和 然后删去
发一波我写的树状数组的树剖
\\((k+1) \\sum c[i] - \\sum x*c[i]\\)
x 与 k 均为 add和get 函数里面 i的初始值
inline void add(int a ,int b)
en[++tot]=b;
nex[tot]=las[a];
las[a]=tot;
inline void ad1(int x,int d)
for(int i=x;i<=n+100;i+=lowbit(i))
c1[i]+=d;
inline void ad2(int x,int d)
for(int i=x;i<=n+100;i+=lowbit(i))
c2[i]=c2[i]+x*d;
inline int get1(int x)
int ans=0;
for(int i=x;i;i-=lowbit(i))
ans=ans+(x+1)*c1[i];
return ans;
inline int get2(int x)
int ans=0;
for(int i=x;i;i-=lowbit(i))
ans+=c2[i];
return ans;
//
#include<bits/stdc++.h>
using namespace std;
#define maxnn 1000000
#define maxn 500100
#define ll long long
#define lowbit(i) i&(-i)
char pbuf[1<<20],*pf=pbuf;
inline void push(char c)
if(pf-pbuf==(1<<20))fwrite(pbuf,1,1<<20,stdout),pf=pbuf;
*pf++=c;
template<typename T>
inline void print(T x)
static short sta[35];
if(x<0)push('-'),x=-x;
int TOP=0;
dosta[TOP++]=x%10;x/=10;while(x);
while(TOP)push('0'+sta[--TOP]);
push('\\n');
char buf[1<<20],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
inline int R()
char t=GC;
int x=0;
while(!isdigit(t)) t=GC;
while(isdigit(t)) x=x*10+t-48,t=GC;
return x;
int c1[maxnn],c2[maxnn];
int las[maxn],en[maxn],tot,nex[maxn];
int n,Q;
inline void add(int a ,int b)
en[++tot]=b;
nex[tot]=las[a];
las[a]=tot;
inline void ad1(int x,int d)
for(int i=x;i<=n+100;i+=lowbit(i))
c1[i]+=d;
inline void ad2(int x,int d)
for(int i=x;i<=n+100;i+=lowbit(i))
c2[i]=c2[i]+x*d;
inline int get1(int x)
int ans=0;
for(int i=x;i;i-=lowbit(i))
ans=ans+(x+1)*c1[i];
return ans;
inline int get2(int x)
int ans=0;
for(int i=x;i;i-=lowbit(i))
ans+=c2[i];
return ans;
int f[maxn][20];
int dfn[maxnn],cnt;
inline int go_up(int s,ll k)
int d=log2(n);
for(int i=d; i>=0; i--)
if(k&(1<<i))
s=f[s][i];
return s;
ll dep[maxnn];
int topp[maxnn];
int son[maxn];
inline int lca(int x,int y)
if(dep[x]<dep[y])
swap(x,y);
int s=dep[x]-dep[y];
x=go_up(x,s);
if(x==y) return y;
s=log2(n);
for(int i=s; i>=0; i--)
if(f[x][i]!=f[y][i])
x=f[x][i];
y=f[y][i];
return f[y][0];
ll size[maxn];
inline void dfs1(int v,int fa)
int maxson=-1;
f[v][0]=fa;
dep[v]=dep[fa]+1;
int s=log2(n);
for(int i=1; i<=s; i++)
f[v][i]=f[f[v][i-1]][i-1];
size[v]=1;
for(int i=las[v]; i; i=nex[i])
int u=en[i];
if(u!=fa)
dfs1(u,v);
size[v]+=size[u];
if(size[u]>maxson)
maxson=size[u];
son[v]=u;
inline void dfs2(int v,int fa,int t)
topp[v]=t;
dfn[v]=++cnt;
if(son[v]) dfs2(son[v],v,t);
for(int i=las[v]; i; i=nex[i])
int u=en[i];
if(u!=fa&&u!=son[v])
dfs2(u,v,u);
inline void add1(int x,int y,int d)
while(topp[x]!=topp[y])
if(dep[topp[x]]<dep[topp[y]])
swap(x,y);
ad1(dfn[topp[x]],d);
ad1(dfn[x]+1,-d);
ad2(dfn[topp[x]],d);
ad2(dfn[x]+1,-d);
x=f[topp[x]][0];
if(dep[x]<dep[y])
swap(x,y);
ad1(dfn[y],d);
ad1(dfn[x]+1,-d);
ad2(dfn[y],d);
ad2(dfn[x]+1,-d);
inline int get(int x,int y)
int ans=0;
while(topp[x]!=topp[y])
if(dep[topp[x]]<dep[topp[y]])
swap(x,y);
int tmp1=dfn[topp[x]];
int tmp2=dfn[x];
ans=ans+(get1(tmp2)-get2(tmp2)-(get1(tmp1-1)-get2(tmp1-1)));
x=f[topp[x]][0];
if(dep[x]<dep[y])
swap(x,y);
int tmp1=dfn[y];
int tmp2=dfn[x];
ans=ans+(get1(tmp2)-get2(tmp2)-(get1(tmp1-1)-get2(tmp1-1)));
return ans;
inline void ch1(int x,int y)
if(dep[x]<dep[y]) swap(x,y);
int now=lca(x,y);
if(now!=y)
add1(now,now,1);
int tmp1=dep[x]-dep[now];
int id1=go_up(x,tmp1-1);
add1(id1,x,1);
tmp1=dep[y]-dep[now];
int id2=go_up(y,tmp1-1);
add1(id2,y,1);
else
add1(y,x,1);
inline ll ch2(int x,int y)
ll ans=0;
if(dep[x]<dep[y]) swap(x,y);
int now=lca(x,y);
if(now!=y)
ans+=get(now,now);
int tmp1=dep[x]-dep[now];
int id1=go_up(x,tmp1-1);
ans+=get(id1,x);
tmp1=dep[y]-dep[now];
int id2=go_up(y,tmp1-1);
ans+=get(id2,y);
else
ans+=get(y,x);
return ans;
inline void era(int x,int y)
if(dep[x]<dep[y]) swap(x,y);
int now=lca(x,y);
if(now!=y)
add1(now,now,-1);
int tmp1=dep[x]-dep[now];
int id1=go_up(x,tmp1-1);
add1(id1,x,-1);
tmp1=dep[y]-dep[now];
int id2=go_up(y,tmp1-1);
add1(id2,y,-1);
else
add1(y,x,-1);
int u;
void FIE()
freopen("overlap1.in","r" ,stdin);
freopen("op.out","w",stdout);
int main()
//FIE();
n=R();
Q=R();
u=R();
int x,y,z;
for(int i=1; i<n; i++)
x=R();
y=R();
add(x,y);
add(y,x);
dfs1(1,0);
dfs2(1,0,1);
while(Q--)
x=R();
z=R();
y=R();
ch1(x,z);
int ans=ch2(y,z);
print(ans);
era(x,z);
fwrite(pbuf,1,pf-pbuf,stdout);
下面是倍增的想法:
注意到终点是固定的
那么也就是说x或者y或者z 应该是与另一个点 到一个汇点 然后再一起到终点的
官方题解:
问题实际上是问树上一个点到另外两点路径的重合长度
树上三点,或是呈一条链的形式,或是存在一个中心,使得中心到三点之间的路径不相交。如下图,上方的两种情况是A、B、C点存在中心O,下方两种情况是A、B、C点在一条链上。对于呈一条链的形式,我们不妨将三个点中,位于中间的那个点称为三个点的中心,如此一来,我们要求的答案实际上是中心到B点的距离。那么,如何求中心呢?通过观察上图,我们发现,中心一定是A、B、C点中两点的LCA。并且,通过进一步观察,我们可以发现,中心是A、B、C点两两的LCA中,深度最大的点。所以,我们只需求出中心,在求出中心到B点的距离即可解决本题。该算法的时间复杂度是O(N+Q)或O((N+Q)*LogN)的。
这题很像紧急集合那道题
询问树上的一个点到其他三个点的距离之和最短
两两lca 深度最大的即为答案
或者也可以分类讨论
假如z在xy与lca的路径之外 答案为lca到z的路径距离
假如z在xy与lca的路径之中 答案为lca到z的路径距离 答案为在这条路径上的点与z的lca到z的距离 可以通过dfs序列和倍增来实现
读题
文件
心态
空间
时间分配
以上是关于1006的主要内容,如果未能解决你的问题,请参考以下文章