zoukankan      html  css  js  c++  java
  • 【最后的测试69测试20161118】【二进制】【思维】【并查集】

      第一题:信(believe.cpp/c/pas)

    背景描述:
      一切死亡都有冗长的回声
              —— 《一切》北岛
      给定一个N个元素的序列A,
      定义Bi = (Ai and A1) + (Ai and A2) + (Ai and A3)+ ...... + (Ai and An)
      定义Ci = (Ai or A1) + (Ai or A2) + ... + (Ai or An)
      求B和C序列。
    输入格式:
      第一行一个整数N表示序列长度
      接下来一行N个整数, 第i个整数为Ai
    输出格式:
      第一行N个整数输出B序列
      第二行N个整数输出C序列
    样例输入:
      4
      3 5 1 1
    样例输出:
      6 8 4 4
      16 22 10 10
    数据规模:
      对于50%的数据, N <= 1000
      对于100%的数据, N <= 100000, Ai <= 100000


    解:做这道题要明白两点:1、每次都有A1~An,所以要考虑整体

                2、因为是求和,所以与相应的每个Ai无关。

      所以 记录一个sum数组表示每一位A[]中为1的个数   。

           & 的情况:Ai当前位为1,那么b[i]为sum[当前位]*(1<<当前位)

        | 的情况:Ai当前位idx为1,c[i]+=n*(1<<(idx-1));当前位为0,则c[i]+=sum[j]*(1<<(j-1));

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 100005
    #define ll long long
    #ifdef WIN32
    #define AUTO "%I64d"
    #else 
    #define AUTO "%lld"
    #endif
    using namespace std;
    ll n;
    ll a[maxn];
    ll b[maxn],c[maxn];
    ll sum[20];
    int main()
    {
        freopen("beleive.in","r",stdin);
        freopen("believe.out","w",stdout);
        scanf(AUTO,&n);
        for (int i=1;i<=n;i++)
        {
            scanf(AUTO,&a[i]);
            ll x=a[i];
            int idx=0;
            while (x>0)
            {
                idx++;
                if ((1&x)) sum[idx]++;
                x>>=1;
            }
        }
        int id=1;
        while (sum[id]) id++;
        for (int i=1;i<=n;i++)
        {
            ll x=a[i];
            int idx=0;
            while (x>0)
            {
                idx++;
                if ((1&x)) {
                    b[i]+=sum[idx]*(1<<(idx-1));
                    c[i]+=n*(1<<(idx-1));
                }
                else {
                    c[i]+=sum[idx]*(1<<(idx-1));
                }
                x>>=1;
            }
            for (int j=idx+1;j<=id;j++)
              c[i]+=sum[j]*(1<<(j-1));//*****
        }
        for (int i=1;i<=n;i++)
          printf(AUTO" ",b[i]);
        printf("
    ");
        for (int i=1;i<=n;i++)
          printf(AUTO" ",c[i]);
        return 0;
    }

    第二题:心(heart.cpp/c/pas)
    背景描述:
      不是一切深渊都是灭亡
      不是一切灭亡都覆盖在弱者的头上
                  ——《这也是一切》 舒婷
      有N个透明的盒子, 每个盒子里面有两个不同颜色的球, 总共有M种颜色。
      Alice和Bob又在玩游戏, 具体的, Alice会从N个盒子里面选出若干个, Bob再从Alice选出的盒子里面选出一些(不能不选), 如果在Bob选出的盒子中, 每  个颜色的球都总共出现了偶数次(0次也是偶数次), 那么Bob胜利, 否则Alice胜利
      在Alice和Bob都足够聪明的情况下, Alice想知道自己在能够获胜的前提下, 第一次最多可以选出几个盒子
    输入格式:
      第一行有两个整数N和M, 意义如题
      接下来N行, 第i+1行两个整数表示第i+1个盒子里面的两个球分别是什么颜色的
    输出格式:
      一行一个整数表示Alice最多可以选多少个盒子
    样例输入:
      3 3
      1 2
      2 3
      2 3
    样例输出:
      2
    数据规模:   对于30%的数据, N <= 10
           对于50%的数据, N <= 20
           对于100%的数据, N <= 100000, M <= 2N


    解:  一眼容易想成其他的算法。画一个图,以颜色为节点,盒子为边,那么边不能重复,不能有环。所以用并查集。考试的时候写了一个kruskal....结果发现思路都错了。。。。

        注意:奇数个相同的盒子也不行,因为B可以只取其中的偶数个,就算你现在选了奇数个,也无法逃过B 的聪明智慧。。。。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 100005
    using namespace std;
    int n,m,fa[maxn<<1],ans;//开两倍 
    int find(int x)
    {
        if (fa[x]!=x) return fa[x]=find(fa[x]);
        return fa[x];
    }
    int main()
    {
        freopen("heart.in","r",stdin);
        freopen("haert.out","w",stdout);
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++)
          fa[i]=i;
        for (int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int r1=find(x);
            int r2=find(y);
            if (r1!=r2)
            {
                ans++;
                fa[r2]=r1;
            }
        }
        printf("%d",ans);
        return 0;
    }

    第三题:题(problem.cpp/c/pas)
    背景描述:
        黑夜给了我黑色的眼睛
        我却用它寻找光明
              ——《一代人》 顾城
      已知一个N个元素的非负整数序列A,
      定义Bi = (Ai and A1) + (Ai and A2) + (Ai and A3)+ ...... + (Ai and An)
      定义Ci = (Ai or A1) + (Ai or A2) + ... + (Ai or An)
      给出B和C序列, 构造一个满足条件的A序列, 如果没有, 输出-1
    输入格式:
      第一行一个整数N。
      接下来一行N个整数表示B序列
      接下来一行N个整数表示C序列
    输出格式:
      如果有解, 输出一行N个整数表示你构造的A序列, SPJ很脆弱, 所以你构造的序列每个整数必须在[0,8191]这个区间内, 我们保证如果有解, 那么一定存在一个解满足每个元素均在[0,8191]内
      否则输出-1
    样例输入:
      4
      6 8 4 4
      16 22 10 10
    样例输出:
      3 5 1 1
    数据规模:
      对于30%的数据, N = 2
      对于70%的数据, N <= 200
      对于100%的数据, N <= 100000, Bi , Ci<= 1000000000


    解:注意一点:& 取的是每一位为1 的交集,| 取的是每一位为 1 的并集。。

      所以A&B+A|B=A+B

      所以Ci+Bi=nAi+sum  (sum:Ai之和)

      ∑(Ci+Bi)=n*sum(Ai相加)+n*sum  (n项B[],C[])

      ∴sum=∑/(2*n)

      ∴就知道Ai=(Ci+Bi-sum)/n

      然后如果不能整除,则输出-1,如果Ai大于INF,则输出-1

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxn 100005
    #define INF 8191
    #define ll long long
    #ifdef WIN32
    #define AUTO "%I64d"
    #else 
    #define AUTO "%lld"
    #endif
    using namespace std;
    ll n,a[maxn],b[maxn],c[maxn],s,sum;
    int main()
    {
        freopen("problem.in","r",stdin);
        freopen("problem.out","w",stdout);
        scanf(AUTO,&n);
        for (int i=1;i<=n;i++){
            scanf(AUTO,&b[i]);    
            s+=b[i];
        }
        for (int i=1;i<=n;i++){
            scanf(AUTO,&c[i]);
            s+=c[i];
        }
        sum=(s/n)>>1;
        if (2*n*sum!=s) {//*******
            printf("-1");
            return 0;    
        }
        for(int i=1;i<=n;i++)
        {
            ll si=b[i]+c[i];
            a[i]=(si-sum)/n;
            if (a[i]>INF){
                printf("-1");
                return 0;    
            } 
        }
        for (int i=1;i<=n;i++)
          printf(AUTO" ",a[i]);
        return 0;
    }

    吐槽:

      这套题叫信心题。。。然后我GG了。

      文件名有毒,输入文件和输出文件名不同,还好我眼尖,不然全班GG。

    明天就考试,马上就出发,GGGGGGGGGGG

  • 相关阅读:
    WINRAR发现溢出漏洞 3.6以下的版本全遭殃!
    Linux桌面即将奢华:KDE 4.1 Beta 1颁发
    AMD Catalyst 8.5 For Linux
    解说MySQL数据库的数据典范和建库战略
    FVWMCrystal:美观且易用的桌面环境
    Linux下建立ISO映像,运用ISO映像,卸载ISO映像
    KDiff3:文件及目次比拟/兼并东西
    Ubuntu 8.04装置nVidia新版显现驱动
    在linux浏览CHM文件
    SCN不差别将会招致ORA00600 2662错误
  • 原文地址:https://www.cnblogs.com/lx0319/p/6077982.html
Copyright © 2011-2022 走看看