• P3773 [CTSC2017]吉夫特


    传送门

    看到组合数在模 $2$ 意义下的乘积,考虑用 $lucas$ 定理把组合数拆开

    $lucas$ 告诉我们,$C(n,m)$ 在模 $k$ 意义下的值,相当于 $n,m$ 在 $k$ 进制下每一位的组合数分别相乘的积在模 $k$ 意义下的值

    就是若 $n=sum_{i=0}a[i]k^i$,$m=sum_{i=0}b[i]k^i$,其中 $a[i],b[i] in [0,k-1]$ ,那么 $C(n,m) equiv prod_{i=0}C(a[i],b[i]) (mod k)$

    所以考虑把每一个组合数二进制拆分,变成一堆 $C(0,0)C(1,0)C(0,1)$ 相乘的形式

    发现若要保证结果为奇数,则一定不能出现 $C(0,1)$ ,不然结果就等于 $0$

    所以组合数为奇数当且仅当对于 $n$ 在二进制下的每一位,若为 $1$ 则 $m$ 在二进制下此位为 $0,1$ 都行,若为 $0$ 则 $m$ 在二进制下此为必须为 $0$

    其实就是,若 $C(n,m)mod 2=1$ 当且仅当 $n & m=m$ ,其中 '&' 表示按位与

    要求 $prod _{i=2}^{k}inom{a_{b_{i-1}}}{a_{b_i}} mod 2>0$ 其实就是对于每一个 $i in [2,k]$,都有 $a_{b_{i-1}} & a_{b_i}=a_{b_i}$

    直接设 $f[i]$ 表示从后往前考虑到第 $i$ 位,满足要求的子序列数量

    转移直接枚举子集暴力转移就好了,注意最后答案要减去子序列长度为 $1$ 的情况

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    typedef long double ldb;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=2e6+7,mo=1e9+7;
    inline int fk(int x) { return x>=mo ? x-mo : x; }
    int n,a[N],pos[N],f[N],ans;
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) a[i]=read(),pos[a[i]]=i;
        for(int i=n;i;i--)
        {
            f[i]=1;
            for(int j=(a[i]-1)&a[i];j;j=(j-1)&a[i])
                f[i]=fk(f[i]+f[pos[j]]);
            ans=fk(ans+f[i]);
        }
        printf("%d
    ",fk(ans-n+mo));
        return 0;
    }
  • 相关阅读:
    现代编程语言:Rust (铁锈,一文掌握钢铁是怎样生锈的)
    mRNA(阅读链接)
    技术的极限(13): 对过程和细节的可视化
    现代编程语言:TypeScript
    现代编程语言:JavaScript
    现代编程语言:zig
    现代编程语言:Python(蛇形遍历一颗树)
    炼金术(9): 简约而不简单,永不停歇的测试 -- always_run
    软件性能测试分析与调优实践之路-Web中间件的性能分析与调优总结
    退役记
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11284584.html
Copyright © 2020-2023  润新知