CF850E Random Elections

题意:一共有n个人,要在三个人中选prefer,一开始他们心中都会想好他们的排名(共6种),之后给出的判断不会矛盾。规则如下:一共有三轮,分别是a->b,b->c,c->a,每个人选1,表示prefer前者,选0表示prefer后者。这样形成一个n位的二进制x。定义函数f(x)={0,1}:1表示这一轮中前者赢,0表示后者赢。

有性质:f(x^((1<<n)-1))=1-f(x)。

现在给出f的对应值表,问其中一个人完胜(赢>=2局)的概率*6^n?n<=20。

 

标程:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int mod=1e9+7;
 4 typedef long long ll;
 5 const int N=1050000;
 6 int n;
 7 ll ans,f[N],x[N];
 8 void fwt()
 9 {
10     for (int i=0;i<n;i++)
11       for (int j=0;j<(1<<n);j++)
12         if (!(j&(1<<i)))
13         {
14             ll l=f[j],r=f[j|(1<<i)];
15             f[j]=l+r,f[j|(1<<i)]=l-r;
16          }
17 }
18 int main()
19 {
20     scanf("%d",&n);char c=getchar();
21     while (c<'0'||c>'9') c=getchar();
22     for (int i=0;i<(1<<n);i++) f[i]=c-'0',c=getchar();
23    fwt();
24    for (int i=0;i<(1<<n);i++) f[i]=f[i]*f[i]; 
25    fwt();
26    for (int i=0;i<(1<<n);i++) f[i]=f[i]>>n;
27    x[0]=1;
28    for (int i=1;i<(1<<n);i++) x[i]=x[i>>1]<<(i&1);//递推求2^popcount(i)
29    for (int i=0;i<(1<<n);i++)
30      ans=((ll)ans+(ll)f[i]*x[i^((1<<n)-1)]%mod)%mod;
31    printf("%d\n",(ll)ans*3%mod);
32     return 0;
33 }

易错点:1.有一点地方少开ll了啊啊啊。低级错误。

 

题解:fwt

写fwt的时候用a[i^j]=sigma(b[i]*c[j])来理解比较容易。

举其中一个人来看,设有关其的两轮他都赢(以下称作A,B),即有一个0一个1的结果(与题目中国的顺序对应)。(最后方案数*3,有三个人)

不能让喜爱排名矛盾,那么我们可以在A,B轮中任意,由此第三轮一些位置固定,一些位置不固定l个,*2^l即可。

运用题目中给的性质,一个0一个1的结果不好处理,但可以与两个1的情况通过一次取反唯一对应。于是可以用fwt统计方案数。由于是按位异或,答案下标的二进制表示中有几个0,即是有几个数不固定。

转载于:https://www.cnblogs.com/Scx117/p/9090360.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值