标签:格式 show 整数 lap color 状压 位运算 utc 数据
魔法之龙玛里苟斯最近在为加基森拍卖师的削弱而感到伤心,于是他想了一道数学题。
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 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 struct bigint{ 6 int a[102],ws; 7 void r(){ 8 for(int i=ws-1;i;--i)if(a[i]&1)a[i-1]+=10; 9 for(int i=ws-1;~i;--i)a[i]>>=1; 10 if(ws&&!a[ws-1])ws--; 11 } 12 int A(){return a[0]&1;} 13 }n; 14 char s[105];int k;const int mod[4]={1,10,100,1000}; 15 void mult(long long &a,long long b){long long modd=1000000000; 16 long long a1=a/modd,a2=a%modd,b1=b/modd,b2=b%modd; 17 b=a2*b2;a=(a1*b2+a2*b1)%modd;a=a*modd+b; 18 while(a&&a%10==0)a/=10; 19 } 20 int main(){//freopen("ex_num2.in","r",stdin);freopen("my.out","w",stdout); 21 int t,l;long long ans,res;scanf("%d",&t);//long long A=2000000001;mult(A,A);printf("%lld\n",A); 22 while(t--){ 23 scanf("%s%d",s,&k);l=strlen(s); 24 ans=1;res=0; 25 for(int i=max(0,l-k-k);i<=l-1;++i)res=res*10+s[i]-48; 26 for(int i=1;i<=res;++i)mult(ans,i); 27 res=1;for(int i=1;i<=mod[k];++i)mult(res,i); 28 n.ws=max(0,l-k-k); 29 for(int i=0;i<n.ws;++i)n.a[i]=s[l-i-k-k-1]-48; 30 for(;n.ws;n.r(),mult(res,res))if(n.A())mult(ans,res); 31 ans%=mod[k]; 32 for(int i=k;i;--i)if(ans/mod[i-1]==0)putchar(‘0‘);else break;if(ans)printf("%lld\n",ans); 33 } 34 }
标签:格式 show 整数 lap color 状压 位运算 utc 数据
原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11625285.html