zoukankan      html  css  js  c++  java
  • 2017北京国庆刷题Day6 afternoon

    期望得分:100+100+40=240

    实际得分:100+0+40=140

     

    二进制拆分、二进制前缀和

    #include<cstdio>
    #include<iostream>
    using namespace std;
    typedef long long LL;
    #define N 100001
    int a[N],b[N],c[N];
    const int mod=1e9+7;
    int suma[N][32],sumb[N][32];
    int bit[31];
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    int finda(int r,int wh)
    {
        long long tot=0;
        for(int i=0;i<=30;i++)
            if(wh&bit[i]) tot=(tot+1ll*(r-suma[r][i])*bit[i])%mod;
            else tot=(tot+1ll*suma[r][i]*bit[i])%mod;
        return int(tot%mod);
    }
    int findb(int r,int wh)
    {
        long long tot=0;
        for(int i=0;i<=30;i++)
            if(wh&bit[i]) tot=(tot+1ll*(r-sumb[r][i])*bit[i])%mod;
            else tot=(tot+1ll*sumb[r][i]*bit[i])%mod;
        return int(tot%mod);
    }
    int main()
    {
        freopen("xorarray.in","r",stdin);
        freopen("xorarray.out","w",stdout);
        int n;
        scanf("%d",&n);
        int len,x;
        for(int i=1;i<=n;i++) 
        {
            read(a[i]); 
            len=0; x=a[i]; 
            while(x) suma[i][len++]=suma[i-1][len]+(x&1),x/=2;
            for(int j=len;j<=30;j++) suma[i][j]=suma[i-1][j];
        }
        for(int i=1;i<=n;i++) 
        {
            read(b[i]); 
            len=0; x=b[i]; 
            while(x) sumb[i][len++]=sumb[i-1][len]+(x&1),x/=2;
            for(int j=len;j<=30;j++) sumb[i][j]=sumb[i-1][j];
        }
        bit[0]=1;
        for(int i=1;i<=30;i++) bit[i]=bit[i-1]<<1;
        c[1]=a[1]^b[1];
        for(int k=2;k<=n;k++)
        {
            c[k]=c[k-1];
            c[k]=(c[k]+finda(k-1,b[k]))%mod;
            c[k]=(c[k]+findb(k,a[k]))%mod;
        }
        for(int i=1;i<=n;i++) printf("%d ",c[i]);
    }
    View Code

    60分做法:

    先做一遍最小生成树

    枚举两个点i,j,那么替换掉的是最小生成树上i,j路径上权值最大的边

    倍增维护

    时间复杂度:O(n*n*logn)

    100分做法:

    换一个角度,考虑被替换掉的边的贡献

    边e要想被替换掉,那么点 i,j 要满足两个条件:

    ① 设e的两端点为u,v,i∈u,j∈v

    ② e的边权是连通 i,j 必经之路(最短路)上边权最大的边

    怎么找这条边?——Kruscal算法

    Kruscal算法每次找还没有加进去的权值最小的边,所以满足必经之路

    还没有加进去的边权最小的边,是已加进去的边权最大的边,所以满足路径上边权最大

    所以,设最小生成树的总权值为sum,设当前边权为w,当前边连接的两点的集合大小分别为 s1、s2

    ans=(sum*n*(n-1)- 2*Σ s1*s2*w)/(n*(n-1))

    n*(n-1):任意选两个点共有这些选法

    Σ 前乘2:u,v 和 v,u 算不同的方案

    #include<cstdio>
    #include<algorithm>
    #define N 20001
    #define M 100001
    using namespace std;
    typedef long long LL;
    int fa[N],siz[N];
    struct node
    {
        int u,v,w;
    }e[M];
    bool cmp(node p,node q)
    {
        return p.w<q.w;
    }
    int find(int i) { return fa[i]==i ? i : fa[i]=find(fa[i]); }
    int main()
    {
        freopen("detective.in","r",stdin);
        freopen("detective.out","w",stdout);
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=n;i++) fa[i]=i,siz[i]=1;
        int u,v;
        LL sum=0,cnt=0;
        for(int i=1;i<=m;i++)
        {
            u=find(e[i].u); v=find(e[i].v);
            if(u==v) continue;
            sum+=e[i].w;
            cnt+=1ll*siz[u]*siz[v]*e[i].w;
            fa[v]=u; siz[u]+=siz[v];
        }
        printf("%.2lf",sum-cnt*2.0/(n*(n-1)));
    }
    View Code

    考场上替换掉的不是 i,j 路径上权值最大的边,替换的是与i,j相连的边权最大的边,0分。

    连接i,j 之后,要满足还是一颗树,去掉i,j之间的任意一条边即可

    分治+DP+bitset

    若点(x1,y1)能访问到点(x2,y2)

    假设x1<=x2,y1<=y2

    那么(x1,y1)往右下扩展,(x2,y2)往左上扩展,两个点一定在中间某一行相遇

    所以可以利用分治的思想枚举相遇的那一行

    如果x1和x2都在枚举的这一行的上面,那就扔到左边

    如果x1和x2都在枚举的这一行的下面,那就扔到右边

    左边和右边的分别继续分治下去

    如果x1和x2一个在上面,一个在下面,那就判断这两个点能否在这一行相遇

    能在这一行相遇,两个点一定能相遇

    反之,一定不能相遇

    如何判断 ?

    假设当前枚举的相遇行为mid,

    f[i][j][k]=0/1表示第i行第j列的点,向右下扩展,能否扩展到第mid行的第k列

    g[i][j][k]=0/1表示第i行第j列的点,向左上扩展,能否扩展到第mid行的第k列

    若 f[x1][y1][k] 和 g[i][j][k] 有一个k同时为true,那么两个点就可以相遇

    第三维可以用bitset简化

    f的转移:

    预处理:f[mid][j][j]=第mid行第j列是否有障碍

    倒叙枚举mid行之上的i,j,f[i][j]|=f[i][j+1],f[i][j]|=f[i+1][j]

    g的转移类似,

    正序枚举mid行之下的,加号改成减号即可

    #include<cstdio>
    #include<vector>
    #include<bitset>
    #define N 501
    #define M 1000001
    using namespace std;
    int n,m;
    bool mp[N][N],ans[M];
    char s[N];
    bitset<N>f[N][N],g[N][N];
    struct node
    {
        int sx,sy,tx,ty,id;
    };
    node p;
    void solve(vector<node>v,int l,int r)
    {
        if(l>r) return;
        int mid=l+r>>1;
        for(int i=mid;i>=l;i--)
            for(int j=m;j;j--)
            {
                f[i][j]=0;
                if(!mp[i][j]) continue;
                if(i==mid) f[i][j].set(j);
                else f[i][j]|=f[i+1][j];
                if(j!=m) f[i][j]|=f[i][j+1];
            }
        for(int i=mid;i<=r;i++)
            for(int j=1;j<=m;j++)
            {
                g[i][j]=0;
                if(!mp[i][j]) continue;
                if(i==mid) g[i][j].set(j);
                else g[i][j]|=g[i-1][j];
                if(j!=1) g[i][j]|=g[i][j-1];
            }
        vector<node>vl,vr;
        for(vector<node>::iterator it=v.begin();it!=v.end();it++)
        {
            p=*it;
            if(p.tx<mid) vl.push_back(p);
            else if(p.sx>mid) vr.push_back(p);
            else ans[p.id]=(f[p.sx][p.sy]&g[p.tx][p.ty]).any();
        }
        solve(vl,l,mid-1);
        solve(vr,mid+1,r);
    }
    int main()
    {
        freopen("boardgame.in","r",stdin);
        freopen("boardgame.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s+1);
            for(int j=1;j<=m;j++) mp[i][j]= s[j]=='.' ? true : false;
        }
        int Q;
        scanf("%d",&Q);
        vector<node>v;
        for(int i=1;i<=Q;i++)
        {
            scanf("%d%d%d%d",&p.sx,&p.sy,&p.tx,&p.ty);
            p.id=i;
            v.push_back(p);
        }
        solve(v,1,n);
        for(int i=1;i<=Q;i++) ans[i] ? puts("Yes") : puts("No");
        return 0;
    }
    View Code

    考场40分双向宽搜,然而跟普通的bfs一个样

    #include<cstdio>
    #include<iostream>
    using namespace std;
    #define N 501
    bool mp[N][N];
    char s[N];
    int n,m,rd[N][N][2];
    int sx,sy,tx,ty;
    int vis[N][N];
    int q[N*N],h,t,cnt,bl[N][N];
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    int turn(int i,int j)
    {
        return (i-1)*m+j;
    }
    bool bfs()
    {
        cnt++; h=0,t=1;
        q[++h]=turn(sx,sy);
        int now,x,y;
        vis[sx][sy]=cnt;
        vis[tx][ty]=cnt;
        q[++t]=turn(tx,ty);
        bl[sx][sy]=1; bl[tx][ty]=2;
        while(h<=t)
        {
            now=q[h++];
            x=(now-1)/m+1; y=now-(x-1)*m;
            if(bl[x][y]==1)
            {
                if(mp[x+1][y])
                {
                    if(bl[x+1][y]==2 && vis[x+1][y]==cnt) return true;
                    if(vis[x+1][y]!=cnt) vis[x+1][y]=cnt,q[++t]=turn(x+1,y),bl[x+1][y]=1;
                }
                if(mp[x][y+1])
                {
                    if(bl[x][y+1]==2 && vis[x][y+1]==cnt) return true;
                    if(vis[x][y+1]!=cnt) vis[x][y+1]=cnt,q[++t]=turn(x,y+1),bl[x][y+1]=1;
                }
            }
            else
            {
                if(mp[x-1][y])
                {
                    if(bl[x-1][y]==1 && vis[x-1][y]==cnt) return true;
                    if(vis[x-1][y]!=cnt) vis[x-1][y]=cnt,q[++t]=turn(x-1,y),bl[x-1][y]=2;
                }
                if(mp[x][y-1])
                {
                    if(bl[x][y-1]==1 && vis[x][y-1]==cnt) return true;
                    if(vis[x][y-1]!=cnt) vis[x][y-1]=cnt,q[++t]=turn(x,y-1),bl[x][y-1]=2;
                }
            }
        }
        return false;
    }
    int main()
    {
        freopen("boardgame.in","r",stdin);
        freopen("boardgame.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s+1);
            for(int j=1;j<=m;j++) mp[i][j]=s[j]=='.' ? true : false;
        }
        int q;
        scanf("%d",&q);
        while(q--)
        {
            read(sx); read(sy); read(tx); read(ty);
            if(!mp[sx][sy] || !mp[tx][ty]) { puts("No"); continue; }
            if(sx==tx && sy==ty) { puts("Yes"); continue; }
            if(tx<=sx && ty<=sy) { puts("No"); continue; }
            if(bfs()) puts("Yes");
            else puts("No");
        }
    }
    View Code
  • 相关阅读:
    Redis 集群方案
    Redis集群搭建
    Java并发问题--乐观锁与悲观锁以及乐观锁的一种实现方式-CAS
    为什么分布式一定要有Redis?
    如何准备Java初级和高级的技术面试
    SpringBoot自动配置原理
    高德地图-- 云图管理台
    GeoJSON格式规范说明
    webGis概念
    npm压缩js文件
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7643157.html
Copyright © 2011-2022 走看看