码迷,mamicode.com
首页 > 其他好文 > 详细

luogu P3773 [CTSC2017]吉夫特

时间:2019-11-11 00:35:34      阅读:102      评论:0      收藏:0      [点我收藏+]

标签:cas   for   --   lin   printf   本质   ora   进制   pre   

luogu

这里的组合数显然要用\(\text{lucas}\)定理来求,所以考虑\(\text{lucas}\)定理的本质,即把\(n,m\)分别拆分成\(p\)进制串\(\{a\}\{b\}\),然后\(\binom{n}{m}\mod p=\prod_i \binom{a_i}{b_i}\mod p\).这题里\(p=2\),那么最后的\(\binom{n}{m}\)要为\(1\),当且仅当\(m\)的二进制串每一位\(\le n\)二进制串的对应位,这相当于\(n\ \&\)(按位与)\(\ m=m\).所以要求的实际上是长度\(\ge2\)的子序列\(\{s_1,s_2...s_k\}\),满足\(\forall i\in[1,k-1] s_i\&s_{i+1}=s_{i+1}\),所以可以倒着扫一遍序列,然后对于当前数记\(f_x\)为子序列最后一项的值为\(x\)的方案,转移枚举\(x\)的子集转移

#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long
#define db long double

using namespace std;
const int N=270000+10,mod=1000000007;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int n,a[N],f[N],ans;
void ad(int &x,int y){x+=y,x-=x>=mod?mod:0;}

int main()
{
    n=rd();
    for(int i=1;i<=n;++i) a[i]=rd();
    for(int i=n;i;--i)
    {
        for(int j=a[i];j;j=(j-1)&a[i]) ad(f[a[i]],f[j]);
        ad(ans,f[a[i]]);
        ad(f[a[i]],1);
    }
    printf("%d\n",ans);
    return 0;
}

luogu P3773 [CTSC2017]吉夫特

标签:cas   for   --   lin   printf   本质   ora   进制   pre   

原文地址:https://www.cnblogs.com/smyjr/p/11832302.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!