下称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; }
来源:https://www.cnblogs.com/Gloid/p/10085209.html