吴传之火烧连营

题目描述
蜀汉章武元年(221年),刘备为报吴夺荆州、关羽被杀之仇,率大军攻吴。吴将陆逊为避其锋,坚守不战,双方成对峙之势。蜀军远征,补给困难,又不能速战速决,加上入夏以后天气炎热,以致锐气渐失,士气低落。刘备为舒缓军士酷热之苦,命蜀军在山林中安营扎寨以避暑热。陆逊看准时机,命士兵每人带一把茅草,到达蜀军营垒时边放火边猛攻。蜀军营寨的木栅和周围的林木为易燃之物,火势迅速在各营漫延。蜀军大乱被吴军连破四十余营。陆逊火烧连营的成功,决定了夷陵之战蜀败吴胜的结果。
刘备带兵深入吴境,陆逊却避而不出,蜀军只得在山林中安营扎寨。而刘备在扎营时却犯了兵家大忌,将兵营排列成一条直线,远远看去,就像是一条串着珠子的链,美其名曰:链寨。如果吴军将领是一般人,那么这也许不算什么,而陆逊何许人也,他可是江东才子,能力不低于周瑜的一代儒将。他看到刘备这样排阵,心生一计,决定用火攻破阵。然而,火计除了要有风,选定引火点也非常重要,对于刘备的布阵,最佳引火点一定是n个兵营中的一个。而因为风水轮流转,每天的最佳引火点都不一样。我们给每个兵营定下一个固定不变的火攻值Ai,每天定下一个风水值K,对于每天的最佳引火点,显然是所有兵营中火攻值与风水值异或的结果最大的那一个兵营。然而,陆逊是个谨慎的人,他要观察时机,在m天中选定一个最佳的进攻的日期,为此他演算出了这m天每天的风水值,然后他希望你能够告诉他这m天每天最大的异或结果。

输入
第一行n,m,代表有n个兵营,m天。
接下来一行有n个非负整数,代表这n个兵营的火攻值。
接下来一行有m个非负整数,代表这m天的风水值。

输出
输出共m行,每行输出一个整数,代表每天最大的异或结果。

样例输入
3 2
1 2 3
4 5
样例输出
7
7
提示
【样例说明】
对于第1天,由于4 xor 1=5, 4 xor 2=6, 4 xor 3=7,最大异或结果为7
对于第2天,由于5 xor 1=4, 5 xor 2=7, 5 xor 3=6,最大异或结果为7

【数据规模和约定】
对于30%数据,n<=1000,m<=1000
对于100%数据,n<=100000,m<=100000, 0<=k,ai<=2147483647

先把n个军营的值统统转化为31位2进制放进trie树,然后以每天的值去贪心,从高位开始,比如当前是0,有1的话就往1走,否则就往0走,因为满足高位肯定比满足所有低位都大。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,x,tot;
int a[35];
struct ty
{
    int Next[2];
    void init()
    {
        memset(Next,-1,sizeof(Next));
    }
}p[3200005];
void work(int x)
{
    int k=0;
    while(x>0) 
    {
        k++;
        a[k]=x%2;
        x=x/2;
    }
    for(int i=k+1;i<=31;i++) a[i]=0;
}
void update()
{
    int now=0;
    for(int i=31;i>=1;i--) 
    {
        int j=a[i];
        if(p[now].Next[j]==-1) 
        {
            tot++;
            p[tot].init();
            p[now].Next[j]=tot;
        }
        now=p[now].Next[j];
    }   
}
int query()
{
    int now=0,ans=0;
    for(int i=31;i>=1;i--) 
    {
        int j=(a[i]^1);
        if(p[now].Next[j]==-1) j=(j^1);
        if((a[i]^j)==1) ans=ans+(1<<(i-1));
        now=p[now].Next[j];
    }
    return ans;
}       
int main()
{
    p[0].init();
    cin>>n>>m;
    for(int i=1;i<=n;i++) 
    {
        scanf("%d",&x);
        work(x);
        update();
    }
    for(int i=1;i<=m;i++) 
    {
        scanf("%d",&x);
        work(x);
        printf("%d\n",query());
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值