【汕头市选2014】舞伴(perm)

55 篇文章 0 订阅
8 篇文章 0 订阅

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

Solution

n才20,很明显的状压嘛
设f[i,s]表示做完前i个男生,女生被匹配的状态为s的方案数
枚举i,s接着枚举第i个男生选了哪个女生,然后转移
但是注意,状态s中1的数量只能是i,所以要注意在这里进行优化时间,否则会超时

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 25
#define ll long long
using namespace std;
int a[N][N],e[21],n,ks[N],en[N];
struct node{
    int x,y;
}k[1048576];
ll mo,f[N][1048576];
bool cnt(node x,node y){return x.y<y.y;}
int main()
{
    freopen("perm.in","r",stdin);
    freopen("perm.out","w",stdout);
    e[0]=1;fo(i,1,20) e[i]=e[i-1]*2;
    fo(s,1,e[20]-1)
    {
        k[s].x=s;fo(j,1,20) if((s & e[j-1])!=0) k[s].y++;
    }
    sort(k+1,k+1048576,cnt);
    fo(s,1,e[20]-1) if(k[s].y!=k[s-1].y) ks[k[s].y]=s,en[k[s].y-1]=s-1;
    en[20]=ks[20];
    scanf("%d %lld",&n,&mo);
    fo(i,1,n) fo(j,1,n) scanf("%d",&a[i][j]);
    f[0][0]=1;
    fo(i,1,n)
    {
        fo(l,ks[i],en[i])
        {
            int s=k[l].x;
            fo(j,1,n)
            if(a[i][j])
            {
                if((s & e[j-1])!=0) 
                f[i][s]=(f[i][s]+f[i-1][s-e[j-1]])%mo;
            }
        }
    }
    printf("%lld\n",f[n][e[n]-1]);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值