I - Nice to Meet You

传送门

和10-17 B 君的第三题 类似,应该算是简化版,给出了固定的点。

f[s]表示只考虑连端都在s集合中的边,s中的固定点(1或者2)能到达整个集合的方案数。

预处理c[s]表示s集合中的总边数,转移就用所有方案减去s集合中有一部分不能到达的方案,也就是枚举一个子集作为能到达的,这个子集的补集和子集之间的边方向确定了,补集内的边随便选,也就和无向图每条边选或者不选等价了。

和无向图不同的是,1能到达的点的集合为s1,2能到达的点的集合为s2的时候,(s1,s2的补集内的边随便定向,补集和s1,s2之间的边方向唯一确定),s1中的任意点不能于s2中的点有连边,因为一个点x不在s2中表明它到s2集合内的点的边都是指向s2的,那么x若在s1中,s1和s2就联通了。

一开始一直wa三个点,因为我固定一个点的时候枚举子集可以为0但是我跳出了。。。

 1 //Achen
 2 #include<bits/stdc++.h>
 3 #define For(i,a,b) for(int i=(a);i<=(b);i++)
 4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
 5 #define Formylove return 0
 6 const int N=32777,p=1e9+7;
 7 typedef long long LL;
 8 typedef double db;
 9 using namespace std;
10 int n,m,a[123],b[123],mp[20][20];
11 LL pr[123],c[N],f[N],to[N];
12 LL ans;
13 
14 template<typename T> void read(T &x) {
15     char ch=getchar(); x=0; T f=1;
16     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
17     if(ch=='-') f=-1,ch=getchar();
18     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
19 }
20 
21 //#define ANS
22 int main() {
23 #ifdef ANS
24     freopen("1.in","r",stdin);
25     freopen("1.out","w",stdout);
26 #endif
27     read(n); read(m);
28     pr[0]=1;
29     For(i,1,120) pr[i]=2LL*pr[i-1]%p;
30     For(i,1,m) {
31         read(a[i]); read(b[i]); 
32         mp[a[i]][b[i]]++;
33         mp[b[i]][a[i]]++;
34         c[pr[a[i]-1]+pr[b[i]-1]]++;
35     }
36     For(i,1,n) {
37         For(j,1,n) if(mp[i][j]) to[pr[i-1]]|=pr[j-1];
38     }
39     int up=pr[n]-1;
40     For(i,0,n-1) For(s,1,up) {
41         if(!(s&pr[i])) {
42             c[s|pr[i]]+=c[s];
43             to[s|pr[i]]|=to[s];
44         }
45     }
46     //For(i,1,up) printf("%d : %d\n",i,to[i]);
47     f[1]=f[2]=1;
48     For(s,3,up) {
49         LL t=0;
50         for(int ss=((s-1)&s);ss;ss=((ss-1)&s)) {
51             if((!(s&2)&&(s&1)&&!(ss&2)&&(ss&1))||(!(s&1)&&(s&2)&&!(ss&1)&&(ss&2))) 
52                 t=(t+f[ss]*pr[c[s^ss]]%p)%p;
53         }
54         if((!(s&2)&&(s&1))||(!(s&1)&&(s&2))) f[s]=(pr[c[s]]-t+p)%p;
55     }
56     For(s,1,up) if((s&1)&&!(s&2)) {
57         int S=(up^s)-2;
58         for(int ss=S;;ss=((ss-1)&S)) {
59             if((s&to[up^s^ss])!=0||((up^s^ss)&to[s])!=0) {
60                 if(!ss) break; else continue;
61             }
62             ans=(ans+f[s]*f[up^s^ss]%p*pr[c[ss]]%p)%p;
63             if(!ss) break;
64         }
65     }
66     printf("%lld\n",(pr[m]-ans+p)%p);
67     Formylove;
68 }
View Code

猜你喜欢

转载自www.cnblogs.com/Achenchen/p/9835384.html
今日推荐