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

  • 相关阅读:
    131. Palindrome Partitioning
    130. Surrounded Regions
    129. Sum Root to Leaf Numbers
    128. Longest Consecutive Sequence
    125. Valid Palindrome
    124. Binary Tree Maximum Path Sum
    122. Best Time to Buy and Sell Stock II
    121. Best Time to Buy and Sell Stock
    120. Triangle
    119. Pascal's Triangle II
  • 原文地址:https://www.cnblogs.com/lx0319/p/6077982.html
Copyright © 2011-2022 走看看