ZRの#999
ソリューション:
カウント問題は、要件が$ M $ラベル、すべてのプログラムのない最低のラベルである必要があります参照してください。
簡単および除外、および除外を考えたが、このことは素晴らしいことです、あなたが質問を含める排除が必要であることを見ることができますが、どれだけ包含と除外を知らないことができます。元のタイトルの等価形式は次のとおりです。プログラム全体マイナスプログラムの数少なくともではないおもちゃの登場。
そこに、封入排除を考えてみましょう
$ \ bigcup ^ {N} _ {i = 1} a_iを= \和^ {N} _ {k = 1}(-1)^ {K-1} \和_ {1 \当量I_1 <I_2 \ cdots I_K \当量のN} \中間A_ {I_1} \キャップA_ {I_2} \キャップ\ cdots \キャップA _ {I_K} \中間$
F_iとは$ $ $私は$の実施形態では、すべての要素が$ I $の数を設定した状態を示している提供しました。その後、あなたは包除原理をカウントすることができます(私は$ $内のすべての要素を含む必要はありません)。
しかし、問題は、データの比較的大きな範囲である、あなたは維持するために$ FWT $(prefixと高次元の)を使用する必要があります。
コード:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1 << 20
const int p = 1e9 + 7;
int n,m,k,x,res,ans;
int f[N],t[N],cnt[N],flag;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {if (ch == '-')f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
return x * f;
}
int main() {
n = read(),m = read();
flag = (1 << m) - 1;
cnt[0] = 1;
for(int i = 1 ; i <= n ; i++) {
k = read();
res = 0;
for(int j = 1 ; j <= k ; j++) {
x = read();
res |= 1 << (x - 1);
}
++f[res];
}
for(int i = 1 ; i <= m ; i++) {
for(int j = 1 ; j <= flag ; j++) {
if(j & (1 << (i - 1)))
f[j] += f[j ^ (1 << (i - 1))];
}
}
for(int i = 1 ; i <= n ; i++) {
cnt[i] = cnt[i - 1] << 1;
if(cnt[i] >= p) cnt[i] -= p;
}
for(int i = 0 ; i <= flag ; i++) {
t[i] = t[i >> 1] + i & 1;
if(!((m - t[i]) & 1)) ans += cnt[f[i]] - 1;
else ans -= cnt[f[i]] - 1;
if(ans >= p) ans %= p;
else if(ans < 0) ans += p;
}
printf("%d \n",ans);
//system("pause");
return 0;
}