2020牛客暑期多校训练营第六场Binary Vector

该博客讨论了如何计算在n天中选取n个线性独立二进制向量的概率,给出了数学公式和打表法求解思路,并提供了AC代码。文章解释了线性独立的概念,以及求解过程中涉及的概率计算。
摘要由CSDN通过智能技术生成

Binary Vector

原题请看这里

题目描述:

A A A = = = { \{ { 0 , 1 0,1 0,1 } \} },每天 R o u n d g o d Roundgod Roundgod A n A^n An ( ( ( 即维度为n,每一位由01组成的所有向量的集合 ) ) )中随机选择一个二进制向量。现在他想知道n天中选取n个线性独立向量的概率。请告诉 R o u n d g o d Roundgod Roundgod每个排列的答案,用 P ⋅ Q − 1 P⋅Q^{-1} PQ1 ( ( ( m o d mod mod 1 0 9 + 7 10^9+7 109+7 ) ) )表示。其中 Q − 1 Q^{-1} Q1 Q Q Q 1 0 9 + 7 10^9+7 109+7的乘法逆元。
f n f_n fn表示 n n n的答案,最后输出 f 1 f_1 f1 ⊕ \oplus f 2 f_2 f2 ⊕ \oplus . . . ... ... ⊕ \oplus f n f_n fn ⊕ \oplus 表示异或。
线性独立介绍
对于问题 B B B A n A^n An是仅包含 0 0 0 1 1 1 n n n维向量

输入描述:

输入包含多个测试用例。 输入的第一行包含一个整数 T T T ( ( ( 1 1 1 ≤ \le T T T ≤ \le 1000 1000 1000 ) ) ),表示测试用例的数量。在接下来的 T T T行中,每行包含一个整数 N N N ( ( ( 1 1 1 ≤ \le N N N ≤ \le 2 ∗ 1 0 7 2*10^7 2107 ) ) ),描述一个测试用例。

输出描述:

对于每个测试用例,输出一个整数来表示答案。

样例输入:

3
1
2
3

样例输出:

500000004
194473671
861464136

说明:

f(1)=1/2
f(2)=3/8
f(3)=21/64

思路:

暴力出奇迹,打表出省一
打表。
2 e 7 2e7 2e7的表。
首先讲一下线性独立,就是说:任意一个向量都不能通过其他向量加减得到,也就是所有的向量都不共面
考虑选取 i i i个向量,对于 i i i,有 2 i 2^i 2i个向量是不与选择的向量独立
那么在一个 n n n维的空间内,选取 i i i个向量共面的概率是 2 i 2 n \frac{2^i}{2^n} 2n2i

那么 n n n维的空间内,选取 i i i个向量线性独立的概率就是 2 n − 2 i 2 n \frac{2^n-2^i}{2^n} 2n2n2i

所以:
f n = f_n= fn= ∏ i = 0 n − 1 \mathop{\prod}\limits_{i=0}^{n-1} i=0n1 2 n − 2 i 2 n \frac{2^n-2^i}{2^n} 2n2n2i
= = = ∏ i = 0 n − 1 \mathop{\prod}\limits_{i=0}^{n-1} i=0n1 2 n − i − 1 2 n − i \frac{2^{n-i}-1}{2^{n-i}} 2ni2ni1
= = = ∏ i = 0 n − 1 \mathop{\prod}\limits_{i=0}^{n-1} i=0n1 2 i − 1 2 i \frac{2^i-1}{2^i} 2i2i1
这样我们就可以打表了。

AC Code:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e7+5;
const int mod=1e9+7;
int T,n,mul[MAXN],inv[MAXN],ans[MAXN],x;
int ksm(int a,int b)
{
    int r=1;
    while(b)
    {
        if(b&1) r=1ll*r*a%mod;
        a=1ll*a*a%mod;
        b>>=1;
    }
    return r;
}
int main()
{
    mul[0]=1;
    for(int i=1;i<=MAXN;i++)
        mul[i]=2ll*mul[i-1]%mod;
    inv[MAXN]=ksm(mul[MAXN],mod-2);
    for(int i=MAXN-1;i;i--)
        inv[i]=2ll*inv[i+1]%mod;
    ans[1]=x=inv[1];
    for(int i=2;i<=MAXN;i++)
    {
        x=1ll*x*(mul[i]-1)%mod*inv[i]%mod;
        ans[i]=ans[i-1]^x;
    }
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        printf("%d\n",ans[n]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值