HZOJ 巨神兵

60pts:

每个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)$;

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<bitset>
 5 #include<vector>
 6 #define LL long long
 7 using namespace std;
 8 const int mod=1e9+7;
 9 struct edge
10 {    
11     int u,v,nxt;
12     #define u(x) ed[x].u
13     #define v(x) ed[x].v
14     #define n(x) ed[x].nxt
15 }ed[10000];
16 int first[21],num_e;
17 #define f(x) first[x]
18 int n,m,ru[21];
19 LL f[1<<11][1<<11];
20 vector<int> fr[21];
21 bool pd(int s,int t)
22 {    
23     bool ok=1;
24     for(int i=1;i<=n;i++)
25     if((1<<i-1)&t)
26     {
27         bool pd2=0;
28         for(int j=0;j<fr[i].size();j++)
29         if((1<<fr[i][j]-1)&s)pd2=1;
30         ok&=pd2;
31     }
32     return ok;
33 }
34 LL find(int s,int po)
35 {
36     int res=0;
37     for(int i=0;i<fr[po].size();i++)
38     if((1<<fr[po][i]-1)&s)res++;
39     return res;
40 }
41 LL poww(LL a,int b);
42 inline void add(int u,int v);
43 signed main()
44 {    
45     cin>>n>>m;int tu,tv;
46     for(int i=1;i<=m;i++)cin>>tu>>tv,add(tu,tv),ru[tv]++,fr[tv].push_back(tu);
47 
48     for(int i=1;i<(1<<n);i++)f[i][i]=1;
49     for(int i=1;i<(1<<n);i++)    
50     {
51         for(int j=1;j<(1<<n);j++)
52         {
53             int s=i&j,t=j&(~i);
54             bitset<3>t1(i),t2(s),t3(t);
55 //            cout<<t1<<" "<<t2<<" "<<(t1|t3)<<" "<<t3<<endl;
56             if(s&&t&&pd(s,t))
57             {
58                 int ch1=1,ch2=1;
59                 for(int k=1;k<=n;k++)
60                 if((1<<k-1)&t)
61                 {
62                     int cnt1=find(i&(~s),k),cnt2=find(s,k);
63                     ch1=ch1*poww(2,cnt1)%mod;ch2=ch2*(poww(2,cnt2)-1)%mod;
64                 }
65                 f[i|t][t]=((f[i|t][t]+f[i][s]*ch1*ch2)%mod)%mod;
66             }
67 //            cout<<f[i][s]<<" -> "<<f[i|t][t]<<endl;
68         }
69     }
70     LL ans=0;
71 //    for(int i=1;i<(1<<n);i++)    
72         for(int j=1;j<(1<<n);j++)
73             ans=(ans+f[(1<<n)-1][j])%mod;
74     printf("%lld\n",ans);
75 }
76 inline void add(int u,int v)
77 {
78     ++num_e;
79     u(num_e)=u;
80     v(num_e)=v;
81     n(num_e)=f(u);
82     f(u)=num_e;
83 }
84 LL poww(LL a,int b)
85 {    
86     LL ans=1;
87     while(b)
88     {    
89         if(b&1)ans=ans*a%mod;
90         a=a*a%mod;b=b>>1;
91     }
92     return ans;
93 }
View Code

100pts:

考虑将第二维去掉,f[i]表示当前集合为i时的方案数,那么$f[i]=\sum f[i][j]$,如果不记录最后一层的话,每一个j都会被计算进去多次,所以容斥一下就可以了(稍不明白)。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<bitset>
 5 #include<vector>
 6 #define re register
 7 #define co const 
 8 #define rec re co
 9 #define LL long long
10 using namespace std;
11 const int mod=1e9+7;
12 struct edge
13 {    
14     int u,v,nxt;
15     #define u(x) ed[x].u
16     #define v(x) ed[x].v
17     #define n(x) ed[x].nxt
18 }ed[10000];
19 int first[21],num_e;
20 #define f(x) first[x]
21 int n,m,ru[21];
22 LL f[1<<21],g[1<<18];
23 int tem[1<<21][21];
24 vector<int> fr[21];
25 bool pd(int s,int t)
26 {    
27     bool ok=1;
28     for(int i=1;i<=n;i++)
29     if((1<<i-1)&t)
30     {
31         bool pd2=0;
32         for(int j=0;j<fr[i].size();j++)
33         if((1<<fr[i][j]-1)&s)pd2=1;
34         ok&=pd2;
35     }
36     return ok;
37 }
38 LL find(rec int s,rec int po)
39 {
40     int res=0;
41     for(int i=0;i<fr[po].size();i++)
42     if((1<<fr[po][i]-1)&s)res++;
43     return res;
44 }
45 int pw[10010];
46 int siz[1<<21];
47 LL poww(LL a,int b);
48 inline void add(rec int u,rec int v);
49 signed main()
50 {    
51 //    freopen("obelisk9.in","r",stdin);
52     
53     cin>>n>>m;int tu,tv;
54     for(re int i=1;i<=m;i++)scanf("%d%d",&tu,&tv),add(tu,tv),ru[tv]++,fr[tv].push_back(tu);
55 
56     for(re int i=1;i<(1<<n);i++){bitset<21>t(i);siz[i]=t.count();}
57     for(re int i=0;i<(1<<n);i++)for(re int j=1;j<=n;j++)tem[i][j]=find(i,j);
58     f[0]=1;
59     pw[0]=1;for(int i=1;i<=10000;i++)pw[i]=pw[i-1]*2%mod;
60     for(int i=1;i<=n;i++)g[1<<i-1]=i;
61     int tttttt=(1<<n);
62     for(re int i=0;i<tttttt;i++)
63     {
64         int all=(~i)&(tttttt-1);
65         for(re int k=all;k;k=(k-1)&all)
66         {
67             int cnt=0;
68             for(re int j=k;j;j-=(j&-j))
69                 cnt+=tem[i][g[j&-j]];
70             
71             if(siz[k]&1)f[i|k]=(f[i|k]+f[i]*pw[cnt]%mod);
72             else         f[i|k]=(f[i|k]-f[i]*pw[cnt]%mod);
73             if(f[i|k]<0)f[i|k]=f[i|k]%mod+mod;
74             if(f[i|k]>=mod)f[i|k]-=mod;
75         }
76     }
77     
78     printf("%lld\n",(f[(1<<n)-1]%mod+mod)%mod);
79 }
80 inline void add(rec int u,rec int v)
81 {
82     ++num_e;
83     u(num_e)=u;
84     v(num_e)=v;
85     n(num_e)=f(u);
86     f(u)=num_e;
87 }
88 LL poww(LL a,int b)
89 {    
90     LL ans=1;
91     while(b)
92     {    
93         if(b&1)ans=ans*a%mod;
94         a=a*a%mod;b=b>>1;
95     }
96     return ans;
97 }
View Code

猜你喜欢

转载自www.cnblogs.com/Al-Ca/p/11619314.html