Scx117
只一眼,便辽阔了时间。

题意:一共有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,即是有几个数不固定。

posted on 2018-05-25 19:23  Scx117  阅读(161)  评论(0编辑  收藏  举报