枚举集合S的所有定向中,入度为0的集合(要求这个集合是一个独立集),然后可以递归进行了
由于入度为k的方案会被算∑C(k,i)次,所以容斥一下,每个方案乘上(-1)^(|T|+1)
子集卷积:
#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 */
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 */