zoukankan      html  css  js  c++  java
  • 牛客练习赛 66B题解

    前言

    当初思路

    开始没想到异或这么多的性质,于是认为对于每个点(u),可以和它连边的点(v)的点权 (a_v=a_u oplus k)(证明:(ecause) (a_uoplus a_v =k) ( herefore) (a_uoplus a_v oplus a_u=a_u oplus k)(a_v=a_u oplus k)),于是每次将同一个点权的点放在一起,跑一遍dijkstra,然后超时了……(赛后重新提交,显示case通过率为32.00%

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    #include <queue>
    using namespace std;
    
    const int MAXN=1e6+10,MAXLIMIT=1048577;
    
    int n,q,a[MAXN],ans,k,x,y;
    std::vector<int> m[MAXLIMIT];
    bool vis[MAXN];
    int dis[MAXN];
    
    int main(){
        scanf("%d %d",&n,&q);
        for(int i = 1;i <= n;i++){
            scanf("%d",&a[i]);
            m[ a[i] ].push_back(i);
        }
        while(q--){
            scanf("%d %d %d",&k,&x,&y);
            memset(dis,~0xcf,sizeof(dis));
            memset(vis,0,sizeof(vis));
            dis[x] = 0;
            vis[x] = 1;
            ans = MAXN + 10;
            priority_queue <pair<int, int> > q;
            q.push(make_pair(0,x));
            while(!q.empty() && ans > n){
                int t = q.top().second; q.pop();
                int togo = a[t]^k;
                for(int i=0;i < m[togo].size();i++){
                    if(!vis[m[togo][i]]){
                        dis[m[togo][i]] = dis[t]+1;
                        if(m[togo][i] == y){
                            ans=dis[t] + 1;
                            break;
                        }
                        vis[m[togo][i]] = 1;
                        q.push( make_pair( dis[m[togo][i]],m[togo][i] ) );
                    }
                }
            }
            if(ans <= n) printf("%d
    ",ans);
            else printf("-1
    ");
        }
        return 0;
    }
    

    思路

    实际上很简单,答案只有 -1,1,2 三种,我们注意到:对于每个点(u),和它连边的只有一种点权(a_u oplus k),假设这种点为 (v) ,则能和(v) 连边的点权为 (a_v oplus k=a_u oplus k oplus k=a_u) ,这意味着,对于每两个点 (x) , (y) , 要不是 (a_x oplus a_y =k)则答案为1 就是 (a_x==a_y) 且存在 (z) 使 (a_x oplus k=a_z) 则答案为 2 (先通过中转到 (z) ,再去 (y)),否则,答案为-1。

    代码

    一下子变简单了。

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    
    const int MAXN = 1e6+10;
    int n,q,a[MAXN],k,x,y,times[(1<<20) + 10];
    
    int main(){
        scanf("%d %d",&n,&q);
        for(int i = 1;i <= n;i++) scanf("%d",&a[i]),times[ a[i] ]++;//记录每个权值出现次数
        while(q--){
            scanf("%d %d %d",&k,&x,&y);
            if((a[x] ^ a[y]) == 0 && times[(a[x] ^ k)]>0) printf("2
    ");//注意,必须要有中转的点才可输出2
            else if( (a[x]^a[y]^k)==0 ) printf("1
    "); //可以直接连边
            else printf("-1
    ");//不能到达
        }
        return 0;
    }
    
  • 相关阅读:
    2-括号配对问题
    14-会场安排问题
    106-背包问题
    12-喷水装置
    HDU-5170
    HDU-1002
    贪吃蛇
    frame与bounds的区别
    MAC下Android的Eclipse开发环境的搭建
    有些人脸上太多的笑是因为他们心中有太多的泪
  • 原文地址:https://www.cnblogs.com/werner-yin/p/13197211.html
Copyright © 2011-2022 走看看