1. 程式人生 > >jzoj3632 【汕頭市選2014】舞伴(狀壓dp)

jzoj3632 【汕頭市選2014】舞伴(狀壓dp)

【汕頭市選2014】舞伴(perm)

Description

N 個男孩,N 個女孩,男孩和女孩可能是朋友,也可能不是朋友。現在要組成N 對舞伴,要求每對舞

伴都是一男一女,且他們是朋友。

統計不同配對方案的數量,因為結果很大,所以只要求除以M 的餘數。

Input

第1 行,2 個整數N,M。接下來N 行,每行N 個整數Aij,表示第i 個男孩和第j 個女孩的關係。如果他們是朋友,則Aij = 1,否則Aij = 0。

Output

1 個整數,表示所求的值。

Sample Input

3 1000000000

1 1 1

1 1 1

1 1 1

Sample Output

6

Data Constraint

• 對於50% 的資料,N <= 9;

• 對於100% 的資料,1 <= N <= 20, 1 <= M <= 10^9; 0 <= Aij <= 1。

分析:狀壓dp,還挺水。。

程式碼

#include <cstdio>
#define M 1100000
using namespace std;

int n,l[22],r[22];
long long m,f[M];
int bin[22],a[22][22],num[M];

int get(int x)
{
    int s=0;
    while (x>0)
    {
        if
(x%2==1) s++; x/=2; } return s; } int main() { // freopen("perm.in","r",stdin); // freopen("perm.out","w",stdout); scanf("%d%d",&n,&m); bin[1]=1; for (int i=2;i<=21;i++) bin[i]=bin[i-1]*2; for (int i=1;i<=bin[n+1]-1;i++) num[i]=get(i); for
(int i=1;i<=n;i++) for (int j=1;j<=n;j++) scanf("%d",&a[i][j]); for (int i=1;i<=n;i++) { l[i]=l[i-1]+bin[n-i+1]; r[i]=r[i-1]+bin[i]; } f[0]=1; for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) if (a[i][j]) for (int s=l[i];s>=r[i];s--) if (num[s]==i&&(s&bin[j])) f[s]=(f[s]+f[s-bin[j]])%m; } printf("%lld",f[l[n]]); fclose(stdin); fclose(stdout); }