Stand in a Line UVA - 11174(递归+有重复元素的全排列) 线性阶乘逆元

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=b-1;i>=a;i--)

const int maxn=4e4+10;

const int mod=1e9+7;


//线性求阶乘逆元 模板
int pow_mod(int base,int n){
    int ans=1;
    while(n){
        if(n&1)   ans=(ll)ans*base%mod;
        base=(ll)base*base%mod;
        n>>=1;
    }
    return ans%mod;
}

int fac[maxn],inv[maxn];
void init(){
    fac[0]=fac[1]=1;
    rep(i,2,maxn)fac[i]=(ll)fac[i-1]*i%mod;
    rep(i,1,maxn)inv[i]=pow_mod(i,mod-2);

    //线性求阶乘的逆元
    //inv_fac[maxn-1]=pow_mod(fac[maxn-1],mod-2);
    //per(i,0,maxn-1)inv_fac[i]=inv_fac[i+1]*(i+1)%mod;
}

vector<int> vec[maxn];

int num[maxn];bool vis[maxn];
void dfs(int now){
    num[now]=1;
    rep(i,0,vec[now].size()){
        int v=vec[now][i];
        dfs(v);
        num[now]+=num[v];
    }
}
/*
注意 乘法的地方都加上ll
*/

int main(){
    init();

    int T;
    scanf("%d",&T);
    while(T--){

        int n,m;
        scanf("%d %d",&n,&m);
        rep(i,0,n+1)vec[i].clear();
        rep(i,0,m){
            int a,b;
            scanf("%d %d",&a,&b);
            vec[b].push_back(a);
            vis[a]=1;
        }
        rep(i,1,n+1){
            if(!vis[i])vec[0].push_back(i);
            vis[i]=num[i]=0;
        }

        dfs(0);

        int ans=fac[n];
        rep(i,1,n+1)ans=(ll)ans*inv[num[i]]%mod;
        printf("%d\n",ans);
    }
    return 0;
}
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=b-1;i>=a;i--)

const int maxn=4e4+10;

const int mod=1e9+7;


//线性求阶乘逆元 模板
int pow_mod(int base,int n){
    int ans=1;
    while(n){
        if(n&1)   ans=(ll)ans*base%mod;
        base=(ll)base*base%mod;
        n>>=1;
    }
    return ans%mod;
}

int fac[maxn],inv_fac[maxn];
void init(){
    fac[0]=1;           //!!! 注意ll强制类型转换
    rep(i,1,maxn)fac[i]=(ll)fac[i-1]*i%mod;
    inv_fac[maxn-1]=pow_mod(fac[maxn-1],mod-2);//!!!注意ll强制类型转换
    per(i,0,maxn-1)inv_fac[i]=(ll)inv_fac[i+1]*(i+1)%mod;
}

vector<int> vec[maxn];

int num[maxn];bool vis[maxn];

/*
排列组合
考虑递归形式+有重复元素的全排列公式
*/

int dfs(int now){
    num[now]=1;
    int ans=1;
    rep(i,0,vec[now].size()){
        int v=vec[now][i];
        int fv=dfs(v);
        ans=(ll)ans*fv%mod*inv_fac[num[v]]%mod;
        num[now]+=num[v];
        //printf("now:%d v:%d fv:%d ans:%d\n",now,v,fv,ans);
    }
    ans=(ll)ans*fac[num[now]-1]%mod;
    return ans;
}


int main(){
    init();

    int T;
    scanf("%d",&T);
    while(T--){
        int n,m;
        scanf("%d %d",&n,&m);
        rep(i,0,n+1)vec[i].clear();
        rep(i,0,m){
            int a,b;
            scanf("%d %d",&a,&b);
            vec[b].push_back(a);
            vis[a]=1;
        }
        rep(i,1,n+1){
            if(!vis[i])vec[0].push_back(i);
            vis[i]=num[i]=0;
        }
        int ans=dfs(0);
        printf("%d\n",ans);
    }
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值