您的位置:首页 > 其它

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)

#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: