最大值

1701:最大值

时间限制: 1000 ms         内存限制: 262144 KB

【题目描述】

你需要在[0,2n)中选一个整数x,接着把x依次异或m个整数a1~am。

在你选出x后,你的对手需要选择恰好一个时刻(刚选完数时、异或一些数后或是最后),将x变为(ceil(2*x/pow(2,n))+2*x)%pow(2,n)。

你想使x最后尽量大,而你的对手会使x最后尽量小。

你需要求出x最后的最大值,以及得到最大值的初值数量。

【输入】

第一行两个整数n,m。

第二行m个整数a1~am。

【输出】

第一行输出一个整数,表示x最后的最大值。

第二行输出一个整数,表示得到最大值的初值数量。

【输入样例】

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<2n。

 

【题解】

首先分析他对手的操作。发现它即为将x的第一位移到最后一位,前面的位数依次向前左移一位,即为循环左移1位。

发现将异或路径上所有数全部循环左移一位后的异或前缀和异或X等于原始异或前缀和异或X再循环左移一位。

可预处理出对手所有可以操作出的给X异或的值。

将他们按31位从高到低加入01trie中。

遍历trie,如果这一位只有左儿子或右儿子则可将当前答案这一位赋为1,否则为0,在遍历左右儿子。

代码如下:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int qi[N],hou[N],n,m,a[N],nn=1,zong[N],cnt,ans1,ans2;
struct trie
{
    int er[2];
}sh[N*30];
inline int read()
{
    char c=getchar();
    int x=0,f=1;
    while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
    while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
    return x*f;
}
inline int suan(int x)
{
    return ((2*x)/nn+2*x)%nn;
}
inline void insert(int x)
{
    int now=0;
    for(int i=n-1;i>=0;i--)
    {
        int pu=(x>>i)&1;
        if(!sh[now].er[pu]) sh[now].er[pu]=++cnt;
        now=sh[now].er[pu];
    }
}
inline void solve(int now,int daan,int ge)
{
    if(ge==-1)
    {
        if(daan>ans1) ans1=daan,ans2=1;
        else if(daan==ans1) ans2++;
        return;
    }
    if(!sh[now].er[0]) solve(sh[now].er[1],daan|(1<<ge),ge-1);
    else if(!sh[now].er[1]) solve(sh[now].er[0],daan|(1<<ge),ge-1);
    else
    {
        solve(sh[now].er[0],daan,ge-1);
        solve(sh[now].er[1],daan,ge-1);
    }
}
signed main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++) nn*=2; 
    for(int i=1;i<=m;i++) a[i]=read();
    for(int i=1;i<=m;i++)
    {
        qi[i]=qi[i-1]^suan(a[i]);
    }
    for(int i=m;i>=1;i--) hou[i]=hou[i+1]^a[i];
    for(int i=0;i<=m;i++) zong[i]=qi[i]^hou[i+1];
    for(int i=0;i<=m;i++) insert(zong[i]);
    solve(0,0,n-1);
    cout<<ans1<<"\n"<<ans2;
}
posted @ 2020-01-03 20:48  精海臭脚  阅读(474)  评论(0编辑  收藏  举报