洛谷 P4547 & bzoj 5006 随机二分图 —— 状压DP+期望

题目:https://www.luogu.org/problemnew/show/P4547

https://www.lydsy.com/JudgeOnline/problem.php?id=5006

参考博客:https://www.cnblogs.com/yanshannan/p/9452802.html

注意同一个点连出去的两条边本来就不能一起选!

每次调用 map 会很慢!所以修改的时候新定义一个 &tmp,就能过了。

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define il inline
using namespace std;
typedef long long ll;
int rd()
{
  int ret=0,f=1; char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return f?ret:-ret;
}
int const xn=20,xm=(1<<15)+5,mod=1e9+7;
int n,m,bin[16],ct;
map<int,int>f[xm];
struct N{
  int s,t,w;
  N(int s=0,int t=0,int w=0):s(s),t(t),w(w) {}
}ed[1005];
il ll pw(ll a,int b){ll ret=1; for(;b;b>>=1,a=a*a%mod)if(b&1)ret=ret*a%mod; return ret;}
il int upt(int x){while(x>=mod)x-=mod; while(x<0)x+=mod; return x;}
il int dfs(int s,int t)
{
  if(!s&&!t)return 1;
  if(f[s][t])return f[s][t];
  int &tmp=f[s][t];//
  for(int i=1;i<=ct;i++)
    {
      if((ed[i].s<<1)<=s||(ed[i].s|s)!=s||(ed[i].t|t)!=t)continue;//t
      tmp=(tmp+(ll)dfs(s^ed[i].s,t^ed[i].t)*ed[i].w)%mod;
    }
  return tmp=upt(tmp);//-
}
int main()
{
  n=rd(); m=rd();
  bin[0]=1; for(int i=1;i<=15;i++)bin[i]=bin[i-1]*2;
  int inv2=pw(2,mod-2),inv4=pw(4,mod-2);
  for(int i=1,tp,a,b,c,d;i<=m;i++)
    {
      tp=rd(); a=rd(); b=rd();
      ed[++ct]=N(bin[a-1],bin[b-1],inv2);
      if(!tp)continue; c=rd(); d=rd();
      ed[++ct]=N(bin[c-1],bin[d-1],inv2);
      if(a==c||b==d)continue;//!
      if(tp==1)ed[++ct]=N(bin[a-1]|bin[c-1],bin[b-1]|bin[d-1],inv4);
      if(tp==2)ed[++ct]=N(bin[a-1]|bin[c-1],bin[b-1]|bin[d-1],-inv4);
    }
  printf("%lld\n",(ll)dfs(bin[n]-1,bin[n]-1)*bin[n]%mod);
  return 0;
}

 

posted @ 2019-01-11 16:33  Zinn  阅读(213)  评论(0编辑  收藏  举报