每个DAG的拓扑序是唯一的,所以考虑将DAG分层。f[i][j]记录当前选择的节点状态是i,最后一层的节点状态为j(dep取最大)。
初始状态:$f[i][i]=1;i\in [1,1<<n)$。那么我们第一层枚举当前状态i,第二层枚举[1,1<<n)。那么令s=i&j,t=j&(~i),s即为i的一个子集,所以令s为当前的最后一层,t为i
的补集的一个子集,令t为转移后的最后一层,要求s到t中每个点都有边。枚举t中每个点,设ch1为集合$i-s$当前点的边数,ch2为s集合到当前点的边数,转移方程:$f[i$|$t][t]+=f[i][s]*\prod 2^{ch1}*\prod (2^{ch2}-1)$;
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
const int mod=1e9+;
struct edge
{
int u,v,nxt;
#define u(x) ed[x].u
#define v(x) ed[x].v
#define n(x) ed[x].nxt
}ed[];
int first[],num_e;
#define f(x) first[x]
int n,m,ru[];
LL f[<<][<<];
vector
bool pd(int s,int t)
{
bool ok=;
for(int i=;i<=n;i++)
if((<
for(int i=;i<=m;i++)cin>>tu>>tv,add(tu,tv),ru[tv]++,fr[tv].push_back(tu);
for(int i=;i<(<<n);i++)f\[i\]\[i\]=;
for(int i=;i<(<<n);i++)
{
for(int j=;j<(<<n);j++)
{
int s=i&j,t=j&(~i);
bitset<>t1(i),t2(s),t3(t);
// cout<
}
return ans;
}
考虑将第二维去掉,f[i]表示当前集合为i时的方案数,那么$f[i]=\sum f[i][j]$,如果不记录最后一层的话,每一个j都会被计算进去多次,所以容斥一下就可以了(稍不明白)。
#include
#include
#include
#include
#include
#define re register
#define co const
#define rec re co
#define LL long long
using namespace std;
const int mod=1e9+;
struct edge
{
int u,v,nxt;
#define u(x) ed[x].u
#define v(x) ed[x].v
#define n(x) ed[x].nxt
}ed[];
int first[],num_e;
#define f(x) first[x]
int n,m,ru[];
LL f[<<],g[<<];
int tem[<<][];
vector
bool pd(int s,int t)
{
bool ok=;
for(int i=;i<=n;i++)
if((<<i-)&t)
{
bool pd2=;
for(int j=;j<fr[i].size();j++)
if((<<fr[i][j]-)&s)pd2=;
ok&=pd2;
}
return ok;
}
LL find(rec int s,rec int po)
{
int res=;
for(int i=;i<fr[po].size();i++)
if((<<fr[po][i]-)&s)res++;
return res;
}
int pw[];
int siz[<<];
LL poww(LL a,int b);
inline void add(rec int u,rec int v);
signed main()
{
// freopen("obelisk9.in","r",stdin);
cin>>n>>m;int tu,tv;
for(re int i=;i<=m;i++)scanf("%d%d",&tu,&tv),add(tu,tv),ru\[tv\]++,fr\[tv\].push\_back(tu);
for(re int i=;i<(<<n);i++){bitset<>t(i);siz\[i\]=t.count();}
for(re int i=;i<(<<n);i++)for(re int j=;j<=n;j++)tem\[i\]\[j\]=find(i,j);
f\[\]=;
pw\[\]=;for(int i=;i<=;i++)pw\[i\]=pw\[i-\]\*%mod;
for(int i=;i<=n;i++)g\[<<i-\]=i;
int tttttt=(<<n);
for(re int i=;i<tttttt;i++)
{
int all=(~i)&(tttttt-);
for(re int k=all;k;k=(k-)&all)
{
int cnt=;
for(re int j=k;j;j-=(j&-j))
cnt+=tem\[i\]\[g\[j&-j\]\];
if(siz\[k\]&)f\[i|k\]=(f\[i|k\]+f\[i\]\*pw\[cnt\]%mod);
else f\[i|k\]=(f\[i|k\]-f\[i\]\*pw\[cnt\]%mod);
if(f\[i|k\]<)f\[i|k\]=f\[i|k\]%mod+mod;
if(f\[i|k\]>=mod)f\[i|k\]-=mod;
}
}
printf("%lld\\n",(f\[(<<n)-\]%mod+mod)%mod);
}
inline void add(rec int u,rec int v)
{
++num_e;
u(num_e)=u;
v(num_e)=v;
n(num_e)=f(u);
f(u)=num_e;
}
LL poww(LL a,int b)
{
LL ans=;
while(b)
{
if(b&)ans=ans*a%mod;
a=a*a%mod;b=b>>;
}
return ans;
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章