zoukankan      html  css  js  c++  java
  • [毒瘤题]玛里苟斯:线性基,表达式分析,测试点分治

    魔法之龙玛里苟斯最近在为加基森拍卖师的削弱而感到伤心,于是他想了一道数学题。

    S 是一个可重集合,S={a1,a2,…,an}。等概率随机取 S 的一个子集 A={ai1,…,aim}。

    计算出 A 中所有元素异或和 x, 求 xk 的期望。

    如果结果是整数,直接输出。如果结果是小数(显然这个小数是有限的),输出精确值(末尾不加多余的 0)。

    1≤n≤100000,1≤k≤5,ai≥0。最终答案小于 263 。k=1,2,3,4,5 各自占用 20% 的数据

    可视的题面一直不在线。。。求xk的期望也是惊了。

    但是这是大神题。。。同时也是傻逼题。

    说它傻逼是因为出题人&数据真是毒瘤到极致。

    首先点明几个坑点:

    1)这题正解就是测试点分治。

    2)不允许任何精度误差,见输出格式

    3)虽然保证答案不爆long long,但是中间运算量会爆

    出题人又反人类了。

    首先我们明确两个本题的特点:

    一个是在albus就是要第一个出场那道题里就用到的结论。

    另一个是,因为最终的答案不会超过263,而你的计算是要做k次方的,所以输入的数不会超过264/k

    还有虽然让你输出精确小数,但是由第一条结论,所以其实答案撑死是一个.5结尾。

    好,开始讲。

    先考虑分数最多而相对简单的k>=3,由第二条结论,这时候线性基里的数不超过21个。

    那么就可以状压枚举线性基可以表示的所有数了,运用结论一,它们是等概率的。

    概率也可以直接算,貌似挺简单?

    爆零惊喜!!!

    因为ans一直在累加,我说过。。。它中间运算量炸long long了。。。

    所以我手动模拟了一下__int128(毕竟考试不让用),开两个变量,以1<<cnt为进制手动做伪高精。

    k=1的点也勉强可以做??分析一下吧。

    因为每一种子集都会被考虑到,所以考虑我们逐位考虑单独的贡献。

    如果所有数的这一位都是0,那么所有的异或和结果都是0。

    只要有些数的这一位是1,那么不管到底有几个数,选奇数个的概率和选偶数个完全相等,所以贡献是这一位/2。

    那么整个数的贡献就是所有数的或和的一半。

    你以为你拿到20分了?

    15分惊喜!!!

    我再说一遍,答案不超过263,不代表计算量不会爆。

    因为你最后除2了,所以之前你会得到264

    然后你要是开long long的话就负了。。。

    跪模(裱)出题人。

    好吧,你活过来了。

    还差最后一个k=2。

    二次方,不能状压,也不能想刚才那么简单做,怎么办?

    平方式展开还是经常用的。

    这时候线性基有32位数。

    我们不断枚举每一位的贡献肯定是不够的了,所以我们枚举两位。

    在任意子集中考虑两位,它们的贡献是2i2jbibj,b表示异或和二进制下这一位是1还是0。

    和k=1类似我们考虑所有情况(因为每种子集都会出现)

    如果两位数都没有在这n个数字里出现过,那么显然没有贡献。

    接下来考虑在选出的子集里,第i位为1第j位为0的有a个,反之的有b个,都为1的有c个。

    把它们异或起来的结果就是(a+c&1,b+c&1)。

    如果那个a类数有0个,b类数有0个,那么你只在c类数里面选,上面说过选出奇数个偶数个的概率相等,所以此时有1/2的概率贡献答案。

    如果a类有0个,b类有>0个,那么

    1)如果c是奇数,为了有贡献,b必须是偶数,概率是1/2×1/2=1/4

    2)如果c是偶数,那么第j位一定没贡献,所以贡献的概率是0

    所以a类有0个,b类有>0个时贡献的概率是1/4

    如果a类有>0个,b类有0个,同理也是1/4

    如果ab都>0。

    1)选偶数个c。那么ab都是奇数。贡献的概率是1/2×1/2×1/2=1/8

    2)选奇数个c。那么ab都是偶数。贡献的概率是1/2×1/2×1/2=1/8

    那么在ab都大于0时贡献的总概率是1/8+1/8=1/4

    可以合并一下,就是如果ab都不存在贡献的概率就是1/2,否则就是1/4。

    然后就是代码实现的问题了,求个期望就好了。

    终于可以AC了。

    爆零惊喜!!!

    中间运算量有一次爆了long long。而且我位运算的左移写的是1<<x而不是1ll<<x。。。

    目前为止见过的最毒瘤。。。

    在颓了一半题解之后又WA了一页之后终于干掉了。。。

     1 #include<cstdio>
     2 #define int unsigned long long
     3 int n,k,base[65],x[100005],chg[65],A,ansx,ansy,cnt;
     4 main(){
     5     scanf("%llu%llu",&n,&k);
     6     for(int i=1;i<=n;++i){
     7         scanf("%llu",&x[i]);int X=x[i];A|=x[i];
     8         for(int i=62;~i;--i)if(X&1ll<<i&&!base[i]){base[i]=X;break;}
     9             else if(X&1ll<<i)X^=base[i];
    10     }
    11     if(k==1)printf("%llu",A>>1),puts(A&1?".5":"");
    12     else if(k==2){
    13         for(int j=0;j<32;++j)for(int t=0;t<32;++t)if(A>>j&1&&A>>t&1){
    14             int f=0;for(int i=1;i<=n;++i)if(x[i]>>j&1^x[i]>>t&1){f=1;break;}
    15             if(t+j<1+f)ansy++;else ansx+=1ll<<t+j-f-1;
    16         }
    17         printf("%llu",ansx+(ansy>>1));puts(ansy&1?".5":"");
    18     }else{
    19         for(int i=22;~i;--i)if(base[i])chg[++cnt]=base[i];
    20         for(int i=0;i<1<<cnt;++i){
    21             int tot=0;
    22             for(int j=0;j<cnt;++j)if(i&1<<j)tot^=chg[j+1];
    23             int x=0,y=1;
    24             for(int s=0;s<k;++s)x*=tot,y*=tot,x+=y>>cnt,y&=(1<<cnt)-1;
    25             ansx+=x;ansy+=y;ansx+=ansy>>cnt;ansy&=(1<<cnt)-1;
    26         }
    27         printf("%llu",ansx);puts(ansy?".5":"");
    28     }
    29 }
    View Code
  • 相关阅读:
    项目三.
    项目二
    项目一.
    第三季-第27课-Shell脚本高级编程
    第三季-第26课-守护进程设计
    第三季-第26课-网络并发服务器设计
    第三季-第25课-UDP通讯程序设计
    刷新页面
    css让超出文字省略号
    css3 背景透明
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11625285.html
Copyright © 2011-2022 走看看