Description

铭铭有 \(n\) 个十分漂亮的珠子和若干根颜色不同的绳子. 现在铭铭想用绳子把所有的珠子 连接成一个整体.

现在已知所有珠子互不相同, 用整数 \(1\)\(n\) 编号. 对于第 \(i\) 个珠子和第 \(j\) 个珠子, 可以选择不用绳子连接, 或者在 \(c_{i,j}\) 根不同颜色的绳子中选择一根将它们连接. 如果把珠子看作点, 把绳子看作边, 将所有珠子连成一个整体即为所有点构成一个连通图. 特别地, 珠子不能和自己连接.

铭铭希望知道总共有多少种不同的方案将所有珠子连成一个整体. 由于答案可能很大, 因此 只需输出答案对 \(1000000007\) 取模的结果.

Input

标准输入. 输入第一行包含一个正整数 \(n\), 表示珠子的个数. 接下来 \(n\) 行, 每行包含 \(n\) 个非负整数, 用空格隔开. 这 \(n\) 行中, 第 \(i\) 行第 \(j\) 个数为 \(c_{i,j}\).

Output

标准输出. 输出一行一个整数, 为连接方案数对 \(10^9+7\) 取模的结果.

Sample Input

3
0 2 3
2 0 4
3 4 0

Sample Output

50

Data Range

对于 100% 的数据,\(n \in \mathbb{Z^+}, 0 \leq c_{i,j} \leq 10^9+7, c_{i,j} = c_{j,i}\); 每组数据的 \(n\) 值如下表所示.

ID 1 2 3 4 5 6 7 8 9 10
\(n\) 8 9 9 10 11 12 13 14 15 16

Explanation

有点类似区间动规的子集动规, 但是其实写法更像状压动规......

因为其实就是状态压缩==

如果连这种 SB 题都不会写那还有什么信心去省选 QwQ

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>

#define rep(_var,_begin,_end) for(int _var=_begin;_var<=_end;_var++)
using namespace std;
typedef long long lli;
const int maxN = 20, maxn = 70000; // 65536 max
const lli modr = 1000000007;

#define bin(__x) (1<<(__x))
int n;
lli c[maxN][maxN], dp[maxn], all[maxn];

int main(int argc, char** argv)
{
    scanf("%d", &n);
    rep(i, 1, n) rep(j, 1, n)
        scanf("%lld", &c[i][j]);
    // Dynamic programming with wubsets.
    for (int k = 1; k < bin(n); k++) {
        dp[k] = 1;
        // Connecting amongst the subset itself.
        for (int i = 1; i <= n; i++) if (k & bin(i-1))
            for (int j = 1; j < i; j++) if (k & bin(j-1))
                dp[k] = dp[k] * (c[i][j] + 1) % modr;
        // Finding subsets
        all[k] = dp[k];
        for (int i = k^(k&-k), j = i; j > 0; j = (j-1)&i)
            dp[k] = (dp[k] - all[j] * dp[k^j] % modr + modr) % modr;
    }
    // Result calculated.
    printf("%d\n", dp[bin(n) - 1]);
    return 0;
}