【题解】[LOJ #2264 / 洛谷 P3773] 吉夫特【计数DP】

题目链接

题意

求给定序列有多少长度大于 \(1\) 的子序列,满足 \(\prod_{i=2}^k \dbinom{a_{b[i-1]}}{a_{b[i]}}\)\(a_i\) 互不相同。\(n\leq 211985\)\(a_i\leq 233333\)

题解

根据 Lucas 定理,子序列中前面的数一定是后面的数(二进制下)的超集。于是枚举子集(或超集,取决于 DP 的顺序)转移。因为 \(a_i\) 互不相同,复杂度大概是 \(O(3^k)\)\(k\) 为位数)(假设值很大)。

// Accepted FLOJ 3
// https://floj.tech/submission/144950

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

const int BUF_LEN=1<<19;
struct FastIO{
    char bufi[BUF_LEN+10],*PTi=bufi+BUF_LEN,*PTENDi=bufi+BUF_LEN;
    inline char gc(){
        (PTi==PTENDi)&&(bufi[fread(bufi,1,BUF_LEN,stdin)]=0,PTi=bufi);
        return *(PTi++);
    }
    char bufo[BUF_LEN+10],*PTo=bufo,*PTENDo=bufo+BUF_LEN;
    inline void pc(char c){
        (PTo==PTENDo)&&(fwrite(bufo,1,BUF_LEN,stdout),PTo=bufo);
        *(PTo++)=c;
    }
    void flush(){
        fwrite(bufo,1,PTo-bufo,stdout);
        PTo=bufo;
    }
    ~FastIO(){
        flush();
    }

    template<class T>inline void getint(T &x=0){
        char c=gc();
        int f=1;x=0;
        while(c<'0'||c>'9'){
            if(c=='-')f=-1;
            c=gc();
        }
        while(c>='0'&&c<='9'){
            x=x*10+c-'0'; 
            c=gc();
        }
        if(f==-1)x=-x;
    }
    operator int(){
        int v;getint(v);return v;
    }
    operator long long(){
        long long v;getint(v);return v;
    }
    template<class T>inline void putint(T x=0,char sep=' '){
        char tmp[20],len=0;
        if(x<0)pc('-'),x=-x;
        if(x==0){ pc('0');pc(sep);return; }
        while(x)tmp[len++]=x%10,x/=10;
        for(int i=len-1;~i;--i)pc(tmp[i]|'0');
        pc(sep);
    }
}io;

#define uint unsigned int
const int N=1<<18,mod=1e9+7;
int f[N],a[N];
int main(){
    int n(io);
    for(int i=0;i<n;i++)a[i]=io;
    reverse(a,a+n);
    f[0]=1;
    for(int i=0;i<n;i++){
        int x(a[i]);
        for(int i=x;;i=x&(i-1)){
            f[x]+=f[i];
            f[x]>=mod&&(f[x]-=mod);
            if(!i)break;
        }
    }
    int ans=0;
    for(int i=0;i<N;i++)ans+=f[i],ans>=mod&&(ans-=mod);
    io.putint((ans-n-1+mod)%mod);
}

posted @ 2020-12-31 22:26  破壁人五号  阅读(73)  评论(0编辑  收藏  举报