Codeforces Round #114 (Div. 1) E Wizards and Bets

题目链接:Wizards and Bets

这场CF的D题感觉读不懂,而且过题人数比E题少很多,所以就看的E题了。

题意:一个有向图中,没有出度的边称为 sink,没有入度的边称为 source,且保证其数目相等,并对其按照大小排序分别得到了新的顺序。现在要求 source 中的点与 sink 中的点一一对应,且路径中不存在相交的地方,对于 source 中的两个点 (i, j) ,对应 sink 中的点分别为 (x1, x2),若是序列的逆序数为偶数则得分为 +1,否则为 -1。问所有的不存在相交的边的情况中,可以得到的总分是多少。

题解:刚刚考完研,居然就忘了行列式与逆序数之间的关系。对于相交的边,总存在与其对称的情况把其抵消掉,所以这个情况可以不用考虑,直接计算总的情况即可。定义矩阵 matrix[i][j] 为 source 中的点 i 到 sink 中的点 j 的不同路径数,然后对求这个矩阵的行列式即可。

   其中计算行列式为高斯消元,然后对角线元素相乘,抄了个板子贴了上来。

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

typedef long long LL;

vector<int> g[1005];
LL n,m,p;
LL in[1005],out[1005],pos1[1005],pos2[1005],cnt1,cnt2;
LL matrix[1005][1005],num[1005][1005];
LL vis[1005];
LL sink[1005],sink_num,source[1005],source_num;

void dfs(LL u){
    vis[u]=1;
    if(out[u]==0){
        num[u][u]=1;
    }
    for(LL i=0;i<g[u].size();i++){
        LL v=g[u][i];
        if(!vis[v]) dfs(v);
        for(LL j=0;j<sink_num;j++){
            num[u][sink[j]]=(num[v][sink[j]]+num[u][sink[j]])%p;
        }
    }
}

void solve(LL n){
    LL ans=1,flag=0;
    for(LL i=0;i<n;i++){
        for(LL j=i+1;j<n;j++){
            LL x=i,y=j;
            while(matrix[y][i]){
                LL t=matrix[x][i]/matrix[y][i];
                for(LL k=i;k<n;k++) matrix[x][k]=(matrix[x][k]-matrix[y][k]*t)%p;
                swap(x,y);
            }
            if(x!=i){
                for(LL k=0;k<n;k++) swap(matrix[i][k],matrix[x][k]);
                flag^=1;
            }
        }
        if(matrix[i][i]==0){
            printf("%d\n",0);
            return ;
        }
        else ans=ans*matrix[i][i]%p;
    }

    if(flag!=0) ans*=-1;
    if(ans<0) ans+=p;
    printf("%lld\n",ans);
}

int main(){
    scanf("%lld%lld%lld",&n,&m,&p);
    for(LL i=1;i<=m;i++){
        LL u,v;
        scanf("%lld%lld",&u,&v);
        out[u-1]++;
        in[v-1]++;
        g[u-1].push_back(v-1);
    }
    for(LL i=0;i<n;i++){
        if(in[i]==0){
            pos1[i]=cnt1++;
            source[source_num++]=i;
        }
        if(out[i]==0){
            pos2[i]=cnt2++;
            sink[sink_num++]=i;
        }
    }
    for(LL i=0;i<n;i++) if(in[i]==0) dfs(i);
    for(LL i=0;i<cnt1;i++){
        for(LL j=0;j<cnt2;j++){
            matrix[i][j]=num[source[i]][sink[j]];
        }
    }
    solve(cnt1);


    return 0;
}

 

posted on 2019-01-17 13:23  Psong  阅读(218)  评论(0编辑  收藏  举报

导航