【题解】P11777 [COTS 2013] BOMBONI
P11777 [COTS 2013] 集合求解 / BOMBONI
题意
存在若干个集合(集合数量未知,不存在空集),给定 \(n\),每个集合中元素 \(x\) 满足 \(1 \le x \le n\),你现在已知 \(M\) 个集合内的元素情况。
定义全集 \(U=\{1,2,\dots ,n\}\),这若干个集合间满足两个性质:
- 若集合 \(A\) 存在,那么 \(\complement_UA\) 也存在。
- 对于当前的两个集合 \(A,B\),集合 \(C=A \cup B\) 也存在。
求出最小的集合数量,把它对 \(10^9+9\) 取模的结果。
题解
知识点:集合。
启发:
- 没思路的话先打暴力找规律。
又要求最小,又要计数,仔细思考可以发现问的是所给的集合能通过题中操作产生多少种不同的集合,纯纯的计数题。
结论是过了之后才会证的。
打暴力找规律,发现答案都是形如 \(2^k-1\) 的,于是开始往有关这方面的想。
根据高中集合知识可以知道 \(A \cap B=\complement_U(\complement_UA\cup\complement_U B)\)。
所以虽然题目没给出集合交的操作,但也是可以只用补集和集合并凑出来的。
设 \(S_0=U\),\(S_1\sim S_m\) 为题中给出集合。
这样题意便转化为了用 \(S_0 \sim S_m\) 通过集合交、并操作能凑出多少种不同的集合。
考虑把 \(1\sim n\) 划分为 \(p\) 个集合,使其全体并集为 \(U\),且两两无交,且其任意真子集都不能由 \(S_0\sim S_m\) 通过若干次上述操作得到,则答案就是 \(2^p-1\)。
考虑怎样的集合,满足其任意真子集不能由 \(S_0\sim S_m\) 通过若干次上述操作得到,当且仅当存在一个集合 \(T\) 满足每个元素 \(x\),都有 \(\forall k \in T\),\(x\in S_k\),也就相当于对于 \(i\in [1,n]\) 算出其对应的 \(T\),把 \(T\) 相同的分到一组,设有 \(p\) 组,答案则为 \(2^p-1\)。
这个过程可以用哈希实现。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()
#define N 202505
#define int unsigned long long
const int mod=1e9+9;
int n,m,ha[N];
inline int qpow(int a,int b){
int ans=1;
while(b){
if(b&1){
ans=ans*a%mod;
}
a=a*a%mod;
b>>=1;
}
return ans;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
rep(i,1,m){
int k,x;
cin>>k;
while(k--){
cin>>x;
ha[x]=ha[x]*131+i;
}
}
vector<int>tmp;
rep(i,1,n){
tmp.pb(ha[i]);
}
sort(all(tmp));
tmp.erase(unique(all(tmp)),ed(tmp));
cout<<(qpow(2,sz(tmp))-1+mod)%mod;
return 0;
}

浙公网安备 33010602011771号