[考试练习题]4.16

A. 有限空间跳跃理论

枚举集合S的所有定向中,入度为0的集合(要求这个集合是一个独立集),然后可以递归进行了

由于入度为k的方案会被算∑C(k,i)次,所以容斥一下,每个方案乘上(-1)^(|T|+1)

 子集卷积:

[学习笔记]FWT——快速沃尔什变换

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
using namespace std;
typedef long long ll;
template<class T>il void rd(T &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}

namespace Miracle{
const int N=20+3;
const int M=(1<<20)+5;
const int mod=1e9+7;
int n,m;
int f[N][M],g[N][M];
int ad(int x,int y){
    return x+y>=mod?x+y-mod:x+y;
}
void FMT(int *f){
    for(reg i=0;i<n;++i){
        for(reg s=0;s<(1<<n);++s){
            if(s&(1<<i)) f[s]=ad(f[s],f[s^(1<<i)]);
        }
    }
}
void IFMT(int *f){
    for(reg i=0;i<n;++i){
        for(reg s=0;s<(1<<n);++s){
            if(s&(1<<i)) f[s]=ad(f[s],mod-f[s^(1<<i)]);
        }
    }
}
int to[N],sz[M],safe[M];
int main(){
    rd(n);rd(m);
    for(reg i=0;i<(1<<n);++i){
        sz[i]=sz[i>>1]+(i&1);
    }int x,y;
    for(reg i=1;i<=m;++i){
        rd(x);rd(y);
        --x;--y;
        to[x]|=(1<<y);
        to[y]|=(1<<x);
    }
    for(reg s=0;s<(1<<n);++s){
        safe[s]=1;
        for(reg j=0;j<n;++j){
            if(s&(1<<j)){
                if(to[j]&s) safe[s]=0;
            }
        }
        g[sz[s]][s]=safe[s]*(sz[s]&1?1:mod-1);
    }
    for(reg s=0;s<(1<<n);++s){
        f[0][s]=1;
    }
    for(reg i=1;i<=n;++i){
        FMT(g[i]);
        for(reg j=1;j<=i;++j){
            for(reg s=0;s<(1<<n);++s){
                f[i][s]=ad(f[i][s],(ll)g[j][s]*f[i-j][s]%mod);
            }
        }
        if(i==n) IFMT(f[i]);
    }
    printf("%d\n",f[n][(1<<n)-1]);
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/4/13 19:58:12
*/
View Code

B. 神秘代码

n<=40,其实状态复杂一些乱搞

拼凑分段是没救了,因为位置限制很大

顺序DP?还要状压。。。

但是实际上不用2^n状态

肯定考虑一个链:x,2x,4x,,,,

链长最多是log40+1=6

对于每个长度相同的链,都是地位等价的

所以可以记录k1,k2,k3,k4,k5,k6表示长度为t的链各有多少个

但是为了保证相邻的2倍关系

所以填的数和上一个填的数密切相关

上一个数的倍数不能直接记录(否则就是2^n的了)

但是可以记录上一个数所在的极长链的长度和位置!

这样就可以知道这一个数能填哪一个了。

要么继续填,要么换一个链

注意把原来的链劈成两半

注意最后要还原S原来的状态

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
using namespace std;
typedef long long ll;
#define int long long

template<class T>il void rd(T &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}

namespace Miracle{
const int N=45;
const int base=45;
const int mod=1e9+7;
int n;
char s[N];
unordered_map<ll,ll>f;
ll bin[20];
int ad(int x,int y){
    return (x+y)>=mod?x+y-mod:x+y;
}
ll dfs(int x,ll S){
    // cout<<" x "<<x<<" S "<<S<<endl;
    if(x==n+1) return 1;
    if(f.count(S)) return f[S];
    ll ret=0;
    int p=S%base;S/=base;
    int l=S%base;S/=base;
    // cout<<" p "<<p<<" l "<<l<<endl;
    if(s[x]=='1'){
        // cout<<" must "<<endl;
        if(p>1){
            ll T=S;
            T-=bin[l];T+=bin[p-1];T+=bin[l-p];
            T=(T*base+p-1)*base+p-1;
            ret=ad(ret,dfs(x+1,T));
        }
        if(p<l){
            ll T=S;
            T-=bin[l];T+=bin[p-1];T+=bin[l-p];
            T=(T*base+l-p)*base+1;
            ret=ad(ret,dfs(x+1,T));
        }
    }else{
        // cout<<" not "<<endl;
        for(reg i=1;i<=6;++i){
            // cout<<" chan "<<i<<endl;
            int tot=(S/bin[i]%base)-(i==l);
            if(tot<=0) continue;
            for(reg j=1;j<=i;++j){
                ll T=S;
                T-=bin[l];T+=bin[p-1];T+=bin[l-p];
                T=(T*base+i)*base+j;
                ret=ad(ret,(ll)dfs(x+1,T)*tot%mod);
            }
        }
        for(reg i=1;i<=p-2;++i){
            // cout<<" ismal "<<i<<endl;
            ll T=S;
            T-=bin[l];T+=bin[p-1];T+=bin[l-p];
            T=(T*base+p-1)*base+i;
            ret=ad(ret,dfs(x+1,T));
        }
        for(reg i=p+2;i<=l;++i){
            // cout<<" ibig "<<i<<endl;
            ll T=S;
            T-=bin[l];T+=bin[p-1];T+=bin[l-p];
            T=(T*base+l-p)*base+i-p;
            ret=ad(ret,dfs(x+1,T));
        }
    }
    S=(S*base+l)*base+p;
    return f[S]=ret;
}
void init(){
    bin[1]=1;
    for(reg i=2;i<=8;++i){
        bin[i]=bin[i-1]*base;
    }
}
int main(){
    rd(n);
    scanf("%s",s+2);s[1]='0';
    init();
    ll st=bin[1];
    for(reg i=1;i<=n;i+=2){
        st+=bin[32-__builtin_clz(n/i)];
    }
    st=(st*base+1)*base+1;
    printf("%lld\n",dfs(1,st));
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/4/13 19:58:12
*/
View Code

猜你喜欢

转载自www.cnblogs.com/Miracevin/p/10726379.html