题解 CF1326F2 【Wise Men (Hard Version)】
个人感觉写的比其他题解要详细?
不过这题本质上跟FWT的and卷积没啥关系…不知道某些老哥是怎么理解的…就只是单纯的长得像而已…
首先考虑,对于一个串
那么对于
证明很简单,因为对于生成
值得注意的是,对于一个长度为
考虑如何求
其中
上式的意义在于,对于
注意到
考虑求出
对于
那么就做完了。最后只需对于每个
#include <bits/stdc++.h>
using namespace std ;
#define p_p pop_back
#define p_b push_back
#define vint vector<int>
typedef long long ll ;
const int N = 20 ;
const int M = 1200000 ;
int n ;
int m ;
int tot ;
ll I[M] ;
ll t[M] ;
ll ans[M] ;
ll f[M][N] ;
ll g[N][M] ;
ll res[N * N] ;
int know[N][N] ;
map<vint, int> Id ;
vint part[N * N], now ;
void fmt_or(ll *f, int g){
int i, j ;
for (i = 0 ; i < n ; ++ i)
for (j = 0 ; j <= m ; ++ j)
if (j >> i & 1) f[j] = f[j] + (ll)g * f[j ^ (1 << i)] ;
}
void dfs_part(int st, int big){
if (st == n + 1)
return void(part[Id[now] = ++ tot] = now) ;
if (n - st + 1 >= big){
for (int i = big ; i <= n - st + 1 ; ++ i)
now.p_b(i), dfs_part(st + i, i), now.p_p() ;
}
}
void dp1(){
for (int i = 0 ; i < n ; ++ i) f[1 << i][i + 1] = 1 ;
for (int i = 1 ; i <= m ; ++ i){
int len = 0 ;
for (int j = 1 ; j <= n ; ++ j){
if (1 << (j - 1) & ~i) continue ;
for (int k = 1 ; k <= n ; ++ k){
if (!know[j][k]) continue ;
if (1 << (k - 1) & i) continue ;
f[i | (1 << (k - 1))][k] += f[i][j] ;
}
++ len ;
}
for (int j = 1 ; j <= n ; ++ j)
if (1 << (j - 1) & i) g[len][i] += f[i][j] ;
}
}
void dp2(){
for (int i = 1 ; i <= tot ; ++ i){
memcpy(t, I, sizeof(I)) ;
int o = (int)part[i].size() ;
for (int j = 0 ; j < o ; ++ j)
for (int k = 0 ; k <= m ; ++ k)
t[k] *= g[part[i][j]][k] ;
fmt_or(t, -1) ; res[i] = t[m] ;
}
//for (int i = 1 ; i <= tot ; ++ i) cout << res[i] << " " ; puts("") ;
}
void revalue(){
for (int i = 0 ; i <= m ; ++ i){
now.clear() ;
for (int l = 0, r ; l < n ; l = r + 1){
r = l ;
while ((1 << r) & i && r < n)
++ r ; now.p_b(r - l + 1) ;
}
sort(now.begin(), now.end()) ;
ans[i] = res[Id[now]] ;
}
}
int main(){
cin >> n ;
m = (1 << n) - 1 ;
I[0] = 1 ; fmt_or(I, 1) ;
for (int i = 1 ; i <= n ; ++ i)
for (int j = 1 ; j <= n ; ++ j)
scanf("%1d", &know[i][j]) ; dp1() ;
for (int i = 1 ; i <= n ; ++ i) fmt_or(g[i], 1) ;
/*
for (int i = 1 ; i <= n ; ++ i)
for (int j = 1 ; j <= m ; ++ j)
cout << g[i][j] << " \n"[j == m] ;
*/
dfs_part(1, 1) ; dp2() ; revalue() ;
//for (int j = 1 ; j <= m ; ++ j)
// cout << I[j] << " " ; puts("") ;
((m += 1) >>= 1) -= 1 ;
for (int i = 0 ; i < n ; ++ i)
for (int j = m ; j >= 0 ; -- j)
if (~j >> i & 1){
ans[j] = ans[j] - ans[j | (1 << i)] ;
}
for (int i = 0 ; i <= m ; ++ i)
cout << ans[i] << " \n"[i == m] ;
return 0 ;
}