10月10日|9日考试

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10月10日|9日考试相关的知识,希望对你有一定的参考价值。

big
【题目描述】
你需要在[0,2^n)中选一个整数 x,接着把 x 依次异或 m 个整数
a1~am。
在你选出 x 后,你的对手需要选择恰好一个时刻(刚选完数时、
2x
异或一些数后或是最后)
,将 x 变为(⌊ n ⌋ + 2x) mod 2 n 。
2
你想使 x 最后尽量大,而你的对手会使 x 最后尽量小。
你需要求出 x 最后的最大值,以及得到最大值的初值数量。
【输入数据】
第一行两个整数 n,m。第二行 m 个整数 a1~am
【输出数据】
第一行输出一个整数,表示 x 最后的最大值。
第二行输出一个整数,表示得到最大值的初值数量。
第一个数正确得 6 分,两个数都正确再得 4 分。
【样例输入】
2 3
1 2 3
【样例输出】
1
2
【样例解释】
x=0 时得到 0,x=1 时得到 1,x=2 时得到 1,x=3 时得到 0。【数据范围】
对于 20%的数据,n<=10,m<=100。
对于 40%的数据,n<=10,m<=1000。
对于另外 20%的数据,n<=30,m<=10。
对于 100%的数据 n<=30,m<=100000,0<=ai<2^n。

 

题解:

  看到2^n次方,首先想到2进制分解+tire树,然后考场上还发现了一个规律,(⌊ n ⌋ + 2x) mod 2^n就是将二进制位向前移动一位,然后超过2^n的向0位补齐,但想到这就不会了,我以为要tire树上写一个很难的dp,没想到一个转化。

  我们枚举一个断点x,当然我们暴力做是异或两个数,但是我们可以把前x个数,每个数都按照上面所讲的向前移位,因为位运算不会相互影响,那么先异或这前x个数之后进行转化,和异或这转化后的前x个数是一样的,所以我们用转化过的前x个数,异或后面的m-x个数就得到我们正真想异或的数。因为有m个断点,所以我们就有m个数。

  把m个树构在trie树上,那么考虑遍历这棵tire,剩下的就是简单贪心了,如果当前节点有两个儿子,那么对手一定会让你得不到这一位的1,如果只有一个,那么你就选和这个儿子不同的就行了。

 

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#define MAXN 3500010
using namespace std;
int ch[MAXN][2],t[MAXN],a[MAXN],sum[MAXN],ans[MAXN];
int n,m,num=1,num2=0;

void insert(int x){
    for(int i=1;i<=n;i++) t[i]=(x>>(n-i)&1);
    int now=1;
    for(int i=1;i<=n;i++){
        if(!ch[now][t[i]]) ch[now][t[i]]=++num;
        now=ch[now][t[i]];
    }
}

void dfs(int now,int shu,int dep){
    if(dep<0){
        ans[++num2]=shu;
        return;
    }
    if(!ch[now][0]&&ch[now][1]) dfs(ch[now][1],shu^(1<<dep),dep-1);
    else if(!ch[now][1]&&ch[now][0]) dfs(ch[now][0],shu^(1<<dep),dep-1);
    else{
        dfs(ch[now][0],shu,dep-1);
        dfs(ch[now][1],shu,dep-1);
    }
}

bool cmp(int x,int y){
    return x>y;
}

int b[MAXN];

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) scanf("%d",&a[i]);
    for(int i=m;i>=1;i--) sum[i]=sum[i+1]^a[i];
    int x=0;
    for(int i=0;i<=m;i++){
        x=x^((2*a[i])/(1<<n)+2*a[i])%(1<<n);
        b[i]=x^sum[i+1];
        insert(x^sum[i+1]);
    }
    dfs(1,0,n-1);
    sort(ans+1,ans+num2+1,cmp);
    int cnt=0;
    for(int i=1;i<=num2;i++){
        if(ans[i]==ans[1]) cnt++;
    }
    printf("%d\n%d",ans[1],cnt);
    return 0;
}

 

以上是关于10月10日|9日考试的主要内容,如果未能解决你的问题,请参考以下文章

10月8日至11月底考试安排

鉴定

2019年10月21日课堂测试

ACT公司推出PreACT,备考要从10年级娃娃抓起

2017年上半年软考报名时间汇总(持续更新)

7月29日测试