zoukankan      html  css  js  c++  java
  • Bzoj4894 天赋

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 16  Solved: 16

    Description

    小明有许多潜在的天赋,他希望学习这些天赋来变得更强。正如许多游戏中一样,小明也有n种潜在的天赋,但有
    一些天赋必须是要有前置天赋才能够学习得到的。也就是说,有一些天赋必须是要在学习了另一个天赋的条件下才
    能学习的。比如,要想学会"开炮",必须先学会"开枪"。一项天赋可能有多个前置天赋,但只需习得其中一个就可
    以学习这一项天赋。上帝不想为难小明,于是小明天生就已经习得了1号天赋-----"打架"。于是小明想知道学习完
    这n种天赋的方案数,答案对1,000,000,007取模。
     

    Input

    第一行一个整数n。
    接下来是一个n*n的01矩阵,第i行第j列为1表示习得天赋j的一个前置天赋为i。
    数据保证第一列和主对角线全为0。
    n<=300

    Output

    第一行一个整数,问题所求的方案数。

    Sample Input

    8
    01111111
    00101001
    01010111
    01001111
    01110101
    01110011
    01111100
    01110110

    Sample Output

    72373

    HINT

     

    Source

    图论 基尔霍夫矩阵 高斯消元

    把“点了一个前置技能(或一个前置相同的同级技能),接着点当前技能”看成一条有向边,那么我们要求的就是这个有向图的树形图的数量。

    (度娘告诉我)有向图也可以用矩阵树定理搞。

    敲完以后跑样例,怎么调答案都是0

    输出矩阵看了一下,发现最左边一列全是0,然后注意到树形图的根固定了是1,也许这导致矩阵实际上少了一个元?

    暴力把矩阵往左上平移一单位,再求出行列式,发现就是答案。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<cmath>
     6 #define LL long long
     7 using namespace std;
     8 const int mod=1e9+7;
     9 const int mxn=305;
    10 int f[mxn][mxn];
    11 int n;
    12 char s[mxn];
    13 int ksm(int a,int k){
    14     int res=1;
    15     while(k){
    16         if(k&1)res=(LL)res*a%mod;
    17         a=(LL)a*a%mod;
    18         k>>=1;
    19     }
    20     return res;
    21 }
    22 int solve(int n){
    23     int i,j,k,F=1;
    24     for(i=1;i<=n;i++){
    25         int p=i;
    26         for(j=i;j<=n;j++)if(f[j][i]){p=i;break;}
    27         if(p!=i){for(j=1;j<=n;j++)swap(f[p][j],f[i][j]); F=-F;}
    28         for(j=i+1;j<=n;j++){
    29             LL inv=(LL)f[j][i]*ksm(f[i][i],mod-2)%mod;
    30             for(k=i;k<=n;k++){
    31                 f[j][k]=((LL)f[j][k]-inv*(LL)f[i][k]%mod+mod)%mod;
    32             }
    33         }
    34     }
    35     int res=F;
    36     for(i=1;i<=n;i++)res=(LL)res*f[i][i]%mod;
    37     if(res<0)res+=mod;
    38     return res;
    39 }
    40 int main(){
    41     int i,j;
    42     scanf("%d",&n);
    43     for(i=1;i<=n;i++){
    44         scanf("%s",s+1);
    45         for(j=1;j<=n;j++){
    46             if(s[j]=='1'){
    47                 f[j][j]++;
    48                 f[i][j]--;
    49             }
    50         }
    51     }
    52     for(i=1;i<=n;i++)
    53         for(j=1;j<=n;j++)
    54             f[i][j]=f[i+1][j+1];
    55     LL ans=solve(n-1);
    56     printf("%lld
    ",ans);
    57     return 0;
    58 }
  • 相关阅读:
    Leetcode 349. Intersection of Two Arrays
    hdu 1016 Prime Ring Problem
    map 树木品种
    油田合并
    函数学习
    Leetcode 103. Binary Tree Zigzag Level Order Traversal
    Leetcode 102. Binary Tree Level Order Traversal
    Leetcode 101. Symmetric Tree
    poj 2524 Ubiquitous Religions(宗教信仰)
    pat 1009. 说反话 (20)
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6858788.html
Copyright © 2011-2022 走看看