1. 程式人生 > >BZOJ5006 THUWC2017隨機二分圖(概率期望+狀壓dp)

BZOJ5006 THUWC2017隨機二分圖(概率期望+狀壓dp)

然而 algo pen \n 貢獻 long tchar namespace using

  下稱0類為單邊,1類為互生邊,2類為互斥邊。對於一種匹配方案,考慮其出現的概率*2n後對答案的貢獻,初始為1,如果有互斥邊顯然變為0,否則每有一對互生邊其貢獻*2。於是有一個顯然的dp,即設f[S1][S2]為左邊選取S1右邊選取S2對答案的貢獻。轉移時考慮S1中編號最小的點x與右邊的點y匹配。首先將f[S1-(1<<x)][S2-(1<<y)]統計進去。然後若(x,y)是單邊,或者雖存在互生互斥關系,但其對應邊的左端點還不在S1中或就是x,或右端點還不在S2中或就是y,就不管了;否則若互斥將f[S1-(1<<x)-(1<<x‘)][S2-(1<<y)-(1<<y‘)]減掉,若互生將f[S1-(1<<x)-(1<<x‘)][S2-(1<<y)-(1<<y‘)]加上,其中(x‘,y‘)是(x,y)的對應邊。這樣大概就是C(30,15)*15的。

  但是這只有暴力20分,甚至連空間都開不下。然而滿分做法和他是一個復雜度的。對上面的做法改為記憶化搜索,map存儲狀態就可以了。多了log也多了80分。不是非常理解意義何在。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
#define ll long long
#define
N 15 #define P 1000000007 char getc(){char c=getchar();while ((c<A||c>Z)&&(c<a||c>z)&&(c<0||c>9)) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<0||c>9) {if (c==-) f=-1;c=getchar();}
while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,typ[N][N],match[N][N][2],s[1<<N]; map<int,int> f; void inc(int &x,int y){x+=y;if (x>=P) x-=P;} inline int trans(int n,int m){return n<<N|m;} int solve(int i,int j) { if (f.find(trans(i,j))!=f.end()) return f[trans(i,j)]; int x=i&-i,ans=0; for (int t=j,k=t&-t;t;t^=k,k=t&-t) if ((k&j)&&typ[s[x]][s[k]]>=0) { inc(ans,solve(i^x,j^k)); int u=match[s[x]][s[k]][0],v=match[s[x]][s[k]][1]; if ((u&i)&&(v&j)&&x!=u&&k!=v) { if (typ[s[x]][s[k]]==1) inc(ans,solve(i^x^u,j^k^v)); if (typ[s[x]][s[k]]==2) inc(ans,P-solve(i^x^u,j^k^v)); } } f[trans(i,j)]=ans;return ans; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj5006.in","r",stdin); freopen("bzoj5006.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); memset(typ,255,sizeof(typ)); for (int i=1;i<=m;i++) { int op=read(),x=read()-1,y=read()-1; if (op==0) typ[x][y]=0; else { int p=read()-1,q=read()-1; typ[x][y]=typ[p][q]=op; match[x][y][0]=1<<p,match[x][y][1]=1<<q; match[p][q][0]=1<<x,match[p][q][1]=1<<y; } } for (int i=0;i<n;i++) s[1<<i]=i; f[0]=1; cout<<solve((1<<n)-1,(1<<n)-1); return 0; }

BZOJ5006 THUWC2017隨機二分圖(概率期望+狀壓dp)