题解 Lighthouse(留坑)
板子题,但是不会……容斥该补了
\(m \leqslant 20\),可以状压枚举子集
可以依据集合大小容斥
有环且大小不为 \(n\) 的集合不合法?
柿子暂时不会推,溜了溜了
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 10000010
#define ll long long
#define reg register int
#define fir first
#define sec second
#define make make_pair
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, m;
const ll mod=1e9+7;
namespace force{
ll inv[20];
ll rec[18][1<<18];
bool mp[18][18];
ll dfs(int u, int vis) {
if (vis==(1<<n)-1) {return mp[0][u];}
if (~rec[u][vis]) return rec[u][vis];
ll ans=0;
for (reg i=0; i<n; ++i)
if (mp[u][i] && !(vis&(1<<i))) ans+=dfs(i, vis|(1<<i));
ans%=mod;
rec[u][vis]=ans;
return ans;
}
void solve() {
memset(rec, -1, sizeof(rec));
inv[0]=inv[1]=1;
for (reg i=2; i<=n; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
for (reg i=0; i<n; ++i)
for (reg j=0; j<n; ++j)
if (i!=j) mp[i][j]=1;
for (reg i=1,u,v; i<=m; ++i) {
u=read()-1; v=read()-1;
mp[u][v]=mp[v][u]=0;
}
printf("%lld\n", (dfs(0, 1)%mod*inv[2])%mod);
exit(0);
}
}
namespace task{
pair<int, int> e[N];
int cnt[N], sta[N], stop, fa[N];
ll fac[N], ans, inv[N];
bool vis[N];
inline int find(int p) {return fa[p]==p?p:fa[p]=find(fa[p]);}
void solve() {
fac[0]=fac[1]=1; inv[0]=inv[1]=1; inv[2]=(mod-mod/2)*inv[mod%2]%mod;
for (reg i=1; i<=n; ++i) fac[i]=fac[i-1]*i%mod;
for (reg i=1; i<=n; ++i) fa[i]=i;
for (reg i=1; i<=m; ++i) e[i]=make(read()-1, read()-1);
for (reg s=0,lim=1<<m,k,cnt2,s2; s<lim; ++s) {
//cout<<"for: "<<s<<endl;
bool flag=0; stop=0;
//memset(cnt, 0, sizeof(int)*(n+5));
//memset(vis, 0, sizeof(bool)*(n+5));
//for (reg i=1; i<=n; ++i) fa[i]=i;
while (stop) cnt[sta[stop--]]=0;
for (reg i=0; i<m; ++i) if (s&(1<<i)) {
sta[++stop]=e[i+1].fir;
sta[++stop]=e[i+1].sec;
if (++cnt[e[i+1].fir]>2) goto jump;
if (++cnt[e[i+1].sec]>2) goto jump;
}
//cout<<"s: "<<s<<endl;
while (stop) cnt[sta[stop--]]=0;
for (reg i=0,f1,f2; i<m; ++i) if (s&(1<<i)) {
sta[++stop]=e[i+1].fir;
sta[++stop]=e[i+1].sec;
f1=find(e[i+1].fir), f2=find(e[i+1].sec);
if (f1==f2) flag=1;
fa[f1]=f2;
}
k=0;
for (reg i=0,t; i<m; ++i) if (s&(1<<i)) {
if (!vis[t=find(e[i+1].fir)]) vis[t]=1, ++k;
if (!vis[t=find(e[i+1].sec)]) vis[t]=1, ++k;
}
cnt2=0; s2=s;
if (s) do {s2&=s2-1; ++cnt2;} while (s2);
if (flag) {
if (k!=1 || cnt2!=n) goto jump;
//cout<<"k: "<<bitset<20>(s)<<endl;
for (reg i=0; i<m; ++i) if (s&(1<<i)) ++cnt[e[i+1].fir], ++cnt[e[i+1].sec];
for (reg i=0; i<m; ++i) if (s&(1<<i) && (cnt[e[i+1].fir]!=2||cnt[e[i+1].sec]!=2)) goto jump;
//cout<<"live: "<<bitset<20>(s)<<endl;
}
ans=(ans+(cnt2&1?-1ll:1ll)*(1ll<<k)%mod*fac[max(n-cnt2-1, 0)]%mod)%mod;
jump: ;
while (stop) cnt[sta[stop]]=0, fa[sta[stop]]=sta[stop], vis[sta[stop--]]=0;
}
//cout<<"ans: "<<ans<<endl;
printf("%lld\n", (ans*inv[2]%mod+mod)%mod);
exit(0);
}
}
signed main()
{
n=read(); m=read();
task::solve();
return 0;
}