首页 > 其他分享 >[NOI2021] 路径交点 题解

[NOI2021] 路径交点 题解

时间:2023-08-04 21:34:00浏览次数:30  
标签:int 题解 路径 NOI2021 行列式 交点 顶点 逆序

[NOI2021] 路径交点 题解

题意

给定一张 \(k\) 层的有向图,第 \(i\) 层有 \(n_i\)​ 个顶点,第 ​\(1\) 层与第 \(k\)​ 层顶点数相同。对于第 ​ ​\(j\) \((1 \leq j <k)\) 层的顶点,只会连向第 \(j+1\) 层的顶点。没有边连向第 \(1\) 层的顶点,第 \(k\) 层的顶点不会向其他顶点连边。

现在要选出 \(n_1\) 条路径,每条路径以第 \(1\) 层顶点为起点,第 \(k\) 层顶点为终点,并要求图中的每个顶点至多出现在一条路径中。

我们规定,第 \(i\) 层与第 \(i+1\) 层之间的两条路径 \(P\)、\(Q\) 有交点,当且仅当 \(P_i-Q_i\) 与 \(P_{i+1}-Q_{i+1}\) 异号。其中 \(P_i\)、\(Q_i\) 表示第 \(i\) 层的顶点,\(P_{i+1}\)、\(Q_{i+1}\) 表示第 \(i+1\) 层的顶点。

现让你求出有偶数个交点的路径方案数比有奇数个交点的路径方案数多多少个。

思路

首先,上面的“异号”这一条件完全可以转化为逆序对。奇偶,做差,逆序对……好像行列式欸。事实上,如果只有两层,答案就是行为左部点,列为右部点的行列式的值。我们从求行列式值的层面来考虑。一个 \(n\) 阶行列式 \(A\) 的值可以表示为

\[\sum_{p \in P} (-1)^{k} \prod_{i = 1}^{n} A_{i, p_i} \]

其中 \(p\) 为一个 \(1\) 到 \(n\) 的排列,\(P\) 为 \(1\) 到 \(n\) 的全排列集合,\(k\) 为排列 \(p\) 中逆序对的个数。

我们来考虑这里连乘的含义,其实就是在用左部点去匹配右部点;而这里的逆序对,也就是题目中说的交点数量(这里可以自己画一个行列式理解一下)。那么,最后行列式的值,就是方案数之差。

现在来考虑 \(k\) 层的情况。我们发现,对于从左往右连续的三层 \(1, 2, 3\),有两条路径 \(P\)、\(Q\),我们按总交点数分为两种情况。

  • 当总交点数为偶数时,则应有 \(P_1-Q_1\),\(P_2-Q_2\) 异号且 \(P_2-Q_2\),\(P_3-Q_3\) 异号;或 \(P_1-Q_1\),\(P_2-Q_2\) 同号且 \(P_2-Q_2\),\(P_3-Q_3\) 同号。而这两种情况下,\(P_1-Q_1\) 与 \(P_3-Q_3\) 均为同号。
  • 当总交点数为奇数时,类似的,总有 \(P_1-Q_1\) 与 \(P_3-Q_3\) 异号。
    也就是说交点的奇偶性并不会改变,这一性质同样可以推广到连续 \(k\) 层。

对于任意相邻的两层,我们都可以建立一个行为左部点,列为右部点的邻接矩阵,我们考虑将这 \(k-1\) 个邻接矩阵相乘,得到的新矩阵中的每个元素变为从 \(1\) 到 \(k\) 层的路径方案数,而这时的逆序对数与交点数量奇偶性的关系仍然成立。我们对矩阵进行行列式求值,得到的就是最后答案。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 205;
const int mod = 998244353;

inline int read(){
    int x = 0; char ch = getchar();
    while(ch<'0' || ch>'9') ch = getchar();
    while(ch>='0'&&ch<='9') x = x*10+ch-48, ch = getchar();
    return x;
}
inline int fpow(int a, int b){
    int ret = 1;
    a%=mod;
    while(b){
        if(b & 1){
            ret = (1ll*ret*a)%mod;
        }
        a = (1ll*a*a)%mod;
        b>>=1;
    }
    return ret;
}
struct mat{
    int f[N][N];
    int h, w;
    mat(){memset(f, 0, sizeof(f));}
    int *operator [](int x){return f[x];}
    void init(int th, int tw){
        h = th, w = tw;
    }
    void frs(){
        memset(f, 0, sizeof(f));
    }
    mat operator *(mat B){
        mat t, BT;
        int wb = B.w, hb = B.h;
        for(int i = 1; i<=hb; ++i){
            for(int j = 1; j<=wb; ++j){
                BT[j][i] = B[i][j];
            }
        }
        for(int i = 1; i<=h; ++i){
            for(int j = 1; j<=wb; ++j){
                for(int k = 1; k<=w; ++k){
                    t[i][j] = (1ll*t[i][j]+1ll*f[i][k]*BT[j][k]%mod)%mod;
                }
            }
        }
        t.init(h, wb);
        return t;
    }
    int calc_det(){
        int ret = 1;
        for(int i = 1; i<=h; ++i){
            if(!f[i][i]){
                for(int j = i+1; j<=h; ++j){
                    if(f[j][i]){
                        swap(f[i], f[j]);
                        ret = -ret;
                        break;
                    }
                }
            }
            int inv = fpow(f[i][i], mod-2);
            for(int j = i+1; j<=h; ++j){
                int tmp = 1ll*f[j][i]*inv%mod;
                for(int k = i; k<=h; ++k){
                    f[j][k] = (1ll*f[j][k]-1ll*f[i][k]*tmp%mod)%mod;
                    f[j][k] = (1ll*f[j][k]+mod)%mod;
                }
            }
        }
        for(int i = 1; i<=h; ++i){
            ret = (1ll*ret*f[i][i]%mod);
        }
        ret = (1ll*ret+mod)%mod;
        return ret;
    }
    void print(){
        for(int i = 1; i<=h; ++i, puts("")){
            for(int j = 1; j<=w; ++j){
                printf("%d ", f[i][j]);
            }
        }
    }
}a[N];

int K;
int m[N], n[N];
int T;
int main(){
    T = read();
    while(T--){
        K = read();
        for(int i = 1; i<=K; ++i){
            n[i] = read();
        }
        for(int i = 1; i<K; ++i){
            m[i] = read();
        }
        for(int i = 1; i<K; ++i){
            a[i].init(n[i], n[i+1]);
            a[i].frs();
            for(int j = 1; j<=m[i]; ++j){
                int u = read(), v = read();
                ++a[i][u][v];
            }
        }
        mat ans = a[1];
        for(int i = 2; i<K; ++i){
            ans = ans*a[i];
        }
        printf("%d\n", ans.calc_det());

    }
    return 0;
}

标签:int,题解,路径,NOI2021,行列式,交点,顶点,逆序
From: https://www.cnblogs.com/frostwood/p/17607081.html

相关文章

  • [Luogu P8744] 左孩子右兄弟 题解
    题目大意给定一棵节点个数为\(N\)的多叉树,求其通过"左孩子右兄弟"表示法转化成的二叉树,高度最高是多少。解决思路首先分辨出此题目是树状DP,并了解"左孩子右兄弟"表示法的转换方式,便开始考虑DP的状态转移方程。状态由于每个节点由\(1\)至\(N\)编号,那么就使用\(dp_{k......
  • 【题解】[2023牛客多校] Distance
    题目传送门:[2023牛客多校]Distance题意对于任意两个元素个数相同的set:A、B,每次可以执行以下两种操作之一:将A中的任意元素加一将B中的任意元素加一\(C(A,B)\)含义为将\(A、B\)改变为完全相同的set所需要花费的最小次数;初始给你两个set:\(S、T\),计算\(\sum_{A\subs......
  • P4795 [BalticOI 2018] 基因工程 题解
    题目传送门:Click。蒟蒻看见这道题,想了足足一个小时,过后顿有所悟,故作此篇。首先,看到题目,光是数据就已经达到了\(\operatorname{O}(nm)\)的级别,再看一看数据范围:\(3\leqn,m\leq4,100\)。显然是一道时间复杂度为\(\operatorname{O}(n,m)\)级别的题目。本蒟蒻首先观察了样......
  • 暑期竞赛培训 Day 16 <继续写题解>
    -[1][蓝桥杯2013省A]剪格子洛谷P8601题目描述如图\(1\)所示,\(3\times3\)的格子中填写了一些整数。我们沿着图中的红色线剪开,得到两个部分,每个部分的数字和都是\(60\)。本题的要求就是请你编程判定:对给定的\(m\timesn\)的格子中的整数,是否可以分割为两个部分,使......
  • P4169 题解
    题意二维平面上有\(n\)个点,给你\(m\)次操作,每次操作可以插入一个点或者询问所有点中距离给定点最近的哈密顿距离。\(n,m\le3\times10^5.\)分析这是一道K-DTree的裸题。而对于这道题,我们还需要考虑插入操作。我们给出两种方式:按很多题解的思路,在这棵树上直接按普通......
  • AT_ttpc2015_g 题解
    洛谷的RMJ总是UKE,所以这一题是在ATcoder上做的,记录一,记录二。思路一首先字符串长度一定是\(6\)的倍数,然后判断是否只有\(t\)、\(i\)、\(e\)、\(c\)、\(h\)这五个字符,最后统计一下字符个数就行了。代码(错误):#include<iostream>#include<string>usingnamespacestd;......
  • UVA333 题解
    ##大意:给定一个字符串$s$判断$s$是否符合要求。1.由数字,`-`和大写英文数字`X`,空格组成,`X`代表$10$且只能在最后出现。2.依次相加前面的数字的总和可以被$11$整除,也就是前缀和,而且刚好$s$只有$10$个数字。---##坑点:1.`\r`换行与空格。你写完代码在洛谷......
  • Python爬虫遇到重定向问题解决办法汇总
    在进行Python爬虫任务时,遇到重定向问题是常见的问题之一。重定向是指在发送请求时,服务器会返回一个新的URL,将请求重新定向到该URL。为了帮助您解决这个问题,本文将提供一些实用的解决办法,并给出相关的代码示例,希望能对您的爬虫任务有所帮助。了解重定向问题重定向问题通常是由于网......
  • T1的题解
    一道小清新的思维题!和\(bocchi\)酱一样可爱的喵30pts首先典中典套路:破环成链,数组复制一份。设\(to[i]=\max(\mathbbj)(j\geqi\wedge\sum_{i\leql\leqj}a_l\leqk)\)枚举起始下标,容易想到贪心,考虑前\(i\)个已经确定好怎样分段了,下一个段一定是\([i,to[i]]......
  • P4826 [USACO15FEB] Superbull S题解
    SuperbullS题解题目传送门(可点击)题面题目描述\(Bessie\)和她的朋友们正在一年一度的\(Superbull\)锦标赛中打球,而\(Farmer\)\(John\)负责让比赛尽可能激动人心。总共有N支队伍(\(1\leN\le2000\))参加了\(Superbull\)锦标赛。每个团队都有一个\(1...2^{30}−1\)的团队ID......