2017/10/12模拟赛总结
2017-10-13 08:14
253 查看
题目来自计蒜客2017 NOIP 提高组模拟赛(四)Day1
T1 小X的质数
L和R较大 又有105的询问 对于每次询问只能O(1)或O(log2n)
首先所有质数可以线性筛出来
那么要处理两个质数相乘
不难发现这种情况一定会在线性筛中出现 只要判一下相乘的为质数即可
筛完之后前缀和累一下就可以O(1)回答询问了
O(Rmax+Q)
T2 小X的密室
这就是一个有向边且有限制的图
kmax=10 可以轻松通过状压解决状态的表示
这样也就最多5∗106个点
然后由于边权是1 直接BFS一遍求出到n的最短路即可
O((n+m)∗2kmax)
T3 小X的佛光
看起来就像一个树链剖分维护区间的裸题
也确实可以写 不过会被卡常
要用BIT维护才可以卡过去= =
O(Q∗log22n)
事实上三个点的分布只有几种情况 分类讨论一下就可以了
不难发现最终的答案就是B到三个点两两的LCA中深度最大的那个点的距离
O(Q∗log2n)
Date:2017/10/13
By CalvinJin
T1 小X的质数
L和R较大 又有105的询问 对于每次询问只能O(1)或O(log2n)
首先所有质数可以线性筛出来
那么要处理两个质数相乘
不难发现这种情况一定会在线性筛中出现 只要判一下相乘的为质数即可
筛完之后前缀和累一下就可以O(1)回答询问了
O(Rmax+Q)
#include<bits/stdc++.h> using namespace std; #define N 10000010 int pri ,sum ; bool mark ; void Init(){ int i,j,h=0; for (i=2;i<N;i++){ if (!mark[i]) pri[++h]=i,sum[i]=1; for (j=1;j<=h;j++){ int t=i*pri[j]; if (t>=N) break; mark[t]=1; if (!mark[i]) sum[t]=1; if (!(i%pri[j])) break; } } for (i=1;i<N;i++) sum[i]+=sum[i-1]; } int main(){ Init(); int Case; scanf("%d",&Case); while (Case--){ int l,r; scanf("%d%d",&l,&r); printf("%d\n",sum[r]-sum[l-1]); } return 0; }
T2 小X的密室
这就是一个有向边且有限制的图
kmax=10 可以轻松通过状压解决状态的表示
这样也就最多5∗106个点
然后由于边权是1 直接BFS一遍求出到n的最短路即可
O((n+m)∗2kmax)
#include<bits/stdc++.h> using namespace std; #define N 5010 #define M 11 #define INF (0x3f3f3f3f) struct edge{ int nxt,t,s; }e[6010]; int head ,edge_cnt; void add_edge(int x,int y,int z){ e[edge_cnt]=(edge){head[x],y,z}; head[x]=edge_cnt++; } int n,m,K,a ; struct P1{ struct poi{ int x,y,dis; }; queue<poi>Q; bool vis [1<<M]; void solve(){ int i; Q.push((poi){1,a[1],0}); vis[1][a[1]]=1; while (!Q.empty()){ int x=Q.front().x,y=Q.front().y,z=Q.front().dis; Q.pop(); for (i=head[x];~i;i=e[i].nxt){ int to=e[i].t,val=e[i].s; if ((y&val)^val) continue; int p=y|a[to]; if (vis[to][p]) continue; if (to==n){ printf("%d\n",z+1); return; } vis[to][p]=1; Q.push((poi){to,p,z+1}); } } printf("No Solution\n"); } }P100; int main(){ memset(head,-1,sizeof(head)); scanf("%d%d%d",&n,&m,&K); int i,j; for (i=1;i<=n;i++) for (j=0;j<K;j++){ int x; scanf("%d",&x); if (x) a[i]|=1<<j; } for (i=1;i<=m;i++){ int x,y,t=0; scanf("%d%d",&x,&y); for (j=0;j<K;j++){ int x; scanf("%d",&x); if (x) t|=1<<j; } add_edge(x,y,t); } if (n==1) printf("0\n"); else P100.solve(); return 0; }
T3 小X的佛光
看起来就像一个树链剖分维护区间的裸题
也确实可以写 不过会被卡常
要用BIT维护才可以卡过去= =
O(Q∗log22n)
#include<bits/stdc++.h> using namespace std; #define N 200010 struct edge{ int nxt,t; }e[N<<1]; int head ,edge_cnt; void add_edge(int x,int y){ e[edge_cnt]=(edge){head[x],y}; head[x]=edge_cnt++; } int n,q; struct query{ int a,b,c; }Q ; struct P1{ struct Binary_Indexed_Tree{ int bit1 ,bit2 ; void add(int *bit,int i,int x){ while (i<=n){ bit[i]+=x; i+=i&-i; } } int sum(int *bit,int i){ int res=0; while (i){ res+=bit[i]; i-=i&-i; } return res; } void Add(int l,int r,int t){ add(bit1,l,-t*(l-1)); add(bit1,r+1,t*r); add(bit2,l,t); add(bit2,r+1,-t); } int query(int l,int r){ return sum(bit1,r)-sum(bit1,l-1)+sum(bit2,r)*r-sum(bit2,l-1)*(l-1); } }BIT; int top ,siz ,fa ,son ,dep ,id ,dfs_cnt; void dfs(int x,int f){ siz[x]=1; fa[x]=f; dep[x]=dep[f]+1; int i; for (i=head[x];~i;i=e[i].nxt){ int to=e[i].t; if (to==f) continue; dfs(to,x); siz[x]+=siz[to]; if (siz[to]>siz[son[x]]) son[x]=to; } } void dfs1(int x,int tp){ id[x]=++dfs_cnt; top[x]=tp; if (son[x]) dfs1(son[x],tp); int i; for (i=head[x];~i;i=e[i].nxt){ int to=e[i].t; if (to==fa[x] || to==son[x]) continue; dfs1(to,to); } } void Up(int x,int y,int t){ while (top[x]!=top[y]){ if (dep[top[x]]<dep[top[y]]) swap(x,y); BIT.Add(id[top[x]],id[x],t); x=fa[top[x]]; } if (dep[x]<dep[y]) swap(x,y); BIT.Add(id[y],id[x],t); } void solve(){ dfs(1,0); dfs1(1,1); int i; for (i=1;i<=q;i++){ Up(Q[i].a,Q[i].b,1); int ans=0; int x=Q[i].b,y=Q[i].c; while (top[x]!=top[y]){ if (dep[top[x]]<dep[top[y]]) swap(x,y); ans+=BIT.query(id[top[x]],id[x]); x=fa[top[x]]; } if (dep[x]<dep[y]) swap(x,y); ans+=BIT.query(id[y],id[x]); printf("%d\n",ans); Up(Q[i].a,Q[i].b,-1); } } }P100; int main(){ memset(head,-1,sizeof(head)); int num,i; scanf("%d%d%d",&n,&q,&num); for (i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); add_edge(x,y); add_edge(y,x); } for (i=1;i<=q;i++) scanf("%d%d%d",&Q[i].a,&Q[i].b,&Q[i].c); P100.solve(); return 0; }
事实上三个点的分布只有几种情况 分类讨论一下就可以了
不难发现最终的答案就是B到三个点两两的LCA中深度最大的那个点的距离
O(Q∗log2n)
#include<bits/stdc++.h> using namespace std; #define N 200010 struct edge{ int nxt,t; }e[N<<1]; int head ,edge_cnt; void add_edge(int x,int y){ e[edge_cnt]=(edge){head[x],y}; head[x]=edge_cnt++; } int top ,siz ,fa ,son ,dep ,id ,dfs_cnt; void dfs(int x,int f){ siz[x]=1; fa[x]=f; dep[x]=dep[f]+1; int i; for (i=head[x];~i;i=e[i].nxt){ int to=e[i].t; if (to==f) continue; dfs(to,x); siz[x]+=siz[to]; if (siz[to]>siz[son[x]]) son[x]=to; } } void dfs1(int x,int tp){ id[x]=++dfs_cnt; top[x]=tp; if (son[x]) dfs1(son[x],tp); int i; for (i=head[x];~i;i=e[i].nxt){ int to=e[i].t; if (to==fa[x] || to==son[x]) continue; dfs1(to,to); } } int LCA(int x,int y){ while (top[x]!=top[y]){ if (dep[top[x]]<dep[top[y]]) swap(x,y); x=fa[top[x]]; } return dep[x]<dep[y]?x:y; } int main(){ memset(head,-1,sizeof(head)); int n,q,num,i; scanf("%d%d%d",&n,&q,&num); for (i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); add_edge(x,y); add_edge(y,x); } dfs(1,0); dfs1(1,1); for (i=1;i<=q;i++){ int A,B,C; scanf("%d%d%d",&A,&B,&C); int x=LCA(A,C),y=LCA(B,C),z=LCA(A,B); if (dep[x]<dep[y]) x=y; if (dep[x]<dep[z]) x=z; printf("%d\n",dep[B]+dep[x]-dep[LCA(B,x)]*2+1); } return 0; }
Date:2017/10/13
By CalvinJin
相关文章推荐
- 2017 12 10 cf 个人赛--题解 SDUT 2017 Autumn Single Contest L
- 总结-2017/10/22
- 快速判断一个数能否被1、2、3、4、5、6、7、8、9、10、11、12、13、17、19、23等整除的规律总结
- NOIP2017模拟赛(8) 总结
- 华中农业大学第五届程序设计大赛 【10/12】个人训练总结
- NOIP2017提高组 模拟赛20(总结)
- NOIP2017提高组 模拟赛19(总结)
- 快速判断一个数能否被1、2、3、4、5、6、7、8、9、10、11、12、13、17、19、23等整除的规律总结
- NOIP2017提高组模拟赛5 (总结)
- 12-10工作总结
- 高二&高一模拟赛12 总结
- 2017(6-12)知识总结
- 自考总结-2017-10
- 2017-12-10杭电OJ2013《蟠桃记》
- 2017-2018-12 20155307 《信息安全系统设计基础》第十一周学习总结
- 【2017 4 12 总结】
- Java_10_12课堂总结
- 快速判断一个数能否被1、2、3、4、5、6、7、8、9、10、11、12、13、17、19、23等整除的规律总结
- 快速判断一个数能否被1、2、3、4、5、6、7、8、9、10、11、12、13、17、19、23等整除的规律总结
- 10-4NOIP模拟赛总结