HZOJ 巨神兵
Posted al-ca
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
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
以上是关于HZOJ 巨神兵的主要内容,如果未能解决你的问题,请参考以下文章