第一题:信(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("\n");
    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

 

 posted on 2016-11-18 15:40  qzgxlx  阅读(215)  评论(0编辑  收藏  举报