CF Round 812 F. Lost Array

F. Lost Array

昨天花了好几个小时在瞎搞,还读错题,看错代码,终于是乱搞出来了,闲下来就写篇博客记录一下昨天差点想砸电脑的心态

观察别人神秘的代码,发现如下神秘的性质

对序列子集异或,超集异或,子集异或会使得序列翻转

本人太菜不知道怎么直观的推,只能靠打表看出结论后枚举贡献进行验证

例如

程序如下

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int P=10007;
 int main()
 {
     int n;scanf("%d",&n);
     vector<int> f(1<<n);
     for(int i=0;i<1<<n;++i)f[i]=rand()%P;

     printf("初序列 : ");
     for(auto v:f)printf("%d ",v);
     puts(" ");
     for(int i=0;i<n;++i)for(int j=0;j<1<<n;++j)
        if(j&1<<i)f[j]^=f[j^1<<i];

    for(int i=0;i<n;++i)for(int j=0;j<1<<n;++j)
        if(!(j&1<<i))f[j]^=f[j^1<<i];

    for(int i=0;i<n;++i)for(int j=0;j<1<<n;++j)
        if(j&1<<i)f[j]^=f[j^1<<i];

        printf("终序列 : ");
     for(int i=0;i<1<<n;++i)printf("%d ",f[i]);
 }

题目中问题可以通过一系列转换,转换成已知b的(m-n,m]项,求a的[0,n)项,a的[n,m]全为0,并且对a进行子集异或将得到b

如果知道b的原序列,那么只需要一次超集异或+一次子集异或就能得到a,但很可惜b的前部分缺失,所以得去发掘其他性质

不难发现如果a的[n,m]全为0,那么对原序列b经行超集异或的时候就会使得b的p[0,m-n]全为0。

从结果开始思考,对原序列b进行超集异或的序列称为c,再对c进行子集异或的序列称为d。

其中d的前[0,m-n+1]项为0,而d是c子集异或的结果,并且c[0]=d[0]=0,所以有c[1]=d[1]=0,c[2]=d[2]=0。所以c的前[0,m-n+1]项也是0。

故对残缺序列b进行超集异或得到结果和原序列进行超集异或的结果相同,所以就解决了

当然,不放心的话也可以写个程序试一下,比如

 代码如下

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int P=10007;
 int main()
 {
     int n;scanf("%d",&n);
     vector<int> f(1<<n);
     for(int i=0;i<(1<<n)-10;++i)f[i]=rand()%P;

     printf("初序列 : ");
     for(auto v:f)printf("%d ",v);
     puts(" ");
     for(int i=0;i<n;++i)for(int j=0;j<1<<n;++j)
        if(j&1<<i)f[j]^=f[j^1<<i];

    for(int i=0;i<n;++i)for(int j=0;j<1<<n;++j)
        if(!(j&1<<i))f[j]^=f[j^1<<i];

  /*  for(int i=0;i<n;++i)for(int j=0;j<1<<n;++j)
        if(j&1<<i)f[j]^=f[j^1<<i];*/

        printf("C序列 : ");
     for(int i=0;i<1<<n;++i)printf("%d ",f[i]);
 }

于是就做完了,对于该题有如下代码

当然也可以不用写的这么麻烦,可以写得更简洁许多

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
 
 int main()
 {
     int n;scanf("%d",&n);
     int pos=1,x=1;
     while(n>x)x<<=1,++pos;
     --x;
     vector<int> f(1<<20);
     for(int i=x;i>x-n;--i)
        scanf("%d",&f[i]);
     for(int i=0;i<pos;++i)
        for(int j=x-n+1;j<=x;++j)
        if(!(j&1<<i))f[j]^=f[j^1<<i];
     for(int i=0;i<pos;++i)
        for(int j=x-n+1;j<=x;++j)
        if(j&1<<i)f[j]^=f[j^1<<i];
 
     for(int i=x-n+1;i<=x;++i)printf("%d ",f[i]);
 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值