2017/10/12模拟赛总结

来源:互联网 发布:试客联盟软件 编辑:程序博客网 时间:2024/06/05 14:20

题目来自计蒜客2017 NOIP 提高组模拟赛(四)Day1

T1 小X的质数

LR较大 又有105的询问 对于每次询问只能O(1)O(log2n)
首先所有质数可以线性筛出来
那么要处理两个质数相乘
不难发现这种情况一定会在线性筛中出现 只要判一下相乘的为质数即可
筛完之后前缀和累一下就可以O(1)回答询问了
O(Rmax+Q)

#include<bits/stdc++.h>using namespace std;#define N 10000010int pri[N],sum[N];bool mark[N];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 可以轻松通过状压解决状态的表示
这样也就最多5106个点
然后由于边权是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[N],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[N];struct P1{    struct poi{        int x,y,dis;    };    queue<poi>Q;    bool vis[N][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(Qlog22n)

#include<bits/stdc++.h>using namespace std;#define N 200010struct edge{    int nxt,t;}e[N<<1];int head[N],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[N];struct P1{    struct Binary_Indexed_Tree{        int bit1[N],bit2[N];        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[N],siz[N],fa[N],son[N],dep[N],id[N],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(Qlog2n)

#include<bits/stdc++.h>using namespace std;#define N 200010struct edge{    int nxt,t;}e[N<<1];int head[N],edge_cnt;void add_edge(int x,int y){    e[edge_cnt]=(edge){head[x],y};    head[x]=edge_cnt++;}int top[N],siz[N],fa[N],son[N],dep[N],id[N],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

原创粉丝点击