首页 > 其他分享 >题解:P9041 [PA2021] Fiolki 2

题解:P9041 [PA2021] Fiolki 2

时间:2024-08-22 16:18:58浏览次数:14  
标签:int 题解 P9041 namespace Poly Fiolki inline mod define

\(\text{Link}\)

题意

给定一个 \(n\) 个点 \(m\) 条边的 DAG,定义 \(f(l,r)\) 表示最多选取多少条不相交路径 \((s_i,t_i)\) 满足 \(s_i\in[1,k],t_i\in[l,r]\),其中不能有任意一点同时在两条选出的路径上。对 \(\forall x\in[0,k)\) 求出有多少 \([l,r]\sube(k,n]\) 使得 \(f(l,r)=x\)。

\(n\le 10^5\),\(m\le 10^6\),\(k\le\min(n-1,50)\)。

思路

不相交路径,考虑 LGV 引理。

LGV 引理的内容是:指定起点 \(s_{1\dots k}\) 和终点 \(t_{1\dots k}\),令 \(e_{i,j}\) 表示 \(i\to j\) 的所有路径的边权乘积和,则 \(\det(e_{s_i,t_j})\) 等于每个 \(s_i\to t_{p_i}\) 的不相交路径组的权值和乘以 \((-1)^{\text{inv}(p)}\) 之和,其中 \(p\) 是一个 \([1,k]\) 的排列;而我们需要解决的问题是:指定起点终点集合,从中任意匹配起点终点并要求存在匹配的起点终点之间的不相交路径,求最大匹配数。

注意到我们只需要判断存在性,我们可以指定一个大质数 \(P=10^9+7\),给每条边随机赋上 \([0,P)\) 的权值,则 \(f(l,r)\) 就等于矩阵 \(e_{i,j}(i\in[1,k],j\in[l,r])\) 的秩,即 \(e_{*,j}(j\in[l,r])\) 中最大可取出几组线性无关的向量,这个问题明显需要使用线性基解决。

我们可以使用拓扑排序求出我们需要的 \(e_{i,j}\)。扫描线扫右端点 \(i\),对每个 \(x\in[0,k)\) 求最大的 \(l\) 使得 \(f(l,i)=x\),扫描线加线性基有一个很经典的 trick:记录线性基内每个元素 \(v_i\) 的加入时间 \(t_i\),加入一个元素 \((v,t)\) 的时候,如果现在考虑到的位上 \(i\) 的 \(t_i<t\),则交换 \((v_i,t_i)\) 与 \((v,t)\)。使用此 trick 便可解决本题。

总时间复杂度 \(O(nk^2+mk)\)。

参考代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
    
}
#define pii pair<int,int>
#define mpr make_pair
#define fir first
#define sec second
namespace rad{
    mt19937_64 R(chrono::system_clock::now().time_since_epoch().count());
    inline int Rand(int l,int r){
        uniform_int_distribution<int> distribution(l,r);
        return distribution(R);
    }
}using namespace rad;
const int N=1e5+10,K=50+2,mod=1e9+9;
namespace PolyC{
    #define Poly vector<int>
    inline int qpow(int x,int y){
        int res=1;
        while(y){
            if(y&1) res=1ll*res*x%mod;
            x=1ll*x*x%mod;
            y>>=1;
        }
        return res;
    }
    inline int add(int a,int b){
        return a+b>=mod?a+b-mod:a+b;
    }
    inline int dec(int a,int b){
        return a>=b?a-b:a+mod-b;
    }
    inline Poly operator+(const Poly &a,const Poly &b){
        Poly F=a;
        F.resize(max(a.size(),b.size()));
        for(int i=0;i<b.size();i++)
            F[i]=add(F[i],b[i]);
        return F;
    }
    inline Poly operator-(const Poly &a,const Poly &b){
        Poly F=a;
        F.resize(max(a.size(),b.size()));
        for(int i=0;i<b.size();i++)
            F[i]=dec(F[i],b[i]);
        return F;
    }
    inline Poly operator*(const Poly &a,const int &b){
        Poly F=a;
        for(int i=0;i<F.size();i++)
            F[i]=1ll*F[i]*b%mod;
        return F;
    }
}
using namespace PolyC;
int n,m,k,d[N];
Poly ct[N];
vector<pii>a[N];
inline void bfs(){
    queue<int>q;
    for(int i=1;i<=k;i++)
        ct[i][i-1]=1;
    for(int i=1;i<=n;i++)
        if(!d[i])
            q.push(i);
    while(!q.empty()){
        int x=q.front();
        q.pop();
        for(auto tp:a[x]){
            int t=tp.fir,w=tp.sec;
            ct[t]=ct[t]+ct[x]*w;
            if(!--d[t]) q.push(t);
        }
    }
    for(int i=1;i<=n;i++)
        assert(!d[i]);
}
struct LnB{
    int tim[K];
    Poly v[K];
    inline void ins(Poly vt,int t){
        for(int i=0;i<k;i++){
            if(!vt[i]) continue;
            if(!tim[i]){
                tim[i]=t,v[i]=vt;
                return ;
            }else{
                if(tim[i]<t) swap(tim[i],t),swap(v[i],vt);
                int b=1ll*qpow(v[i][i],mod-2)*vt[i]%mod;
                vt=vt-v[i]*b;
            }
            assert(!vt[i]);
        }
    }
}L;
ll ans[K];
int main(){
    n=read(),m=read(),k=read();
    for(int i=1;i<=m;i++){
        int u=read(),v=read();
        a[u].push_back(mpr(v,Rand(1,mod-1))),d[v]++;
    }
    for(int i=1;i<=n;i++)
        ct[i].resize(k);
    bfs();
    for(int i=k+1;i<=n;i++){
        L.ins(ct[i],i);
        vector<int>vec;
        for(int j=0;j<k;j++)
            if(L.tim[j])
                vec.push_back(L.tim[j]);
        vec.push_back(k),vec.push_back(i);
        sort(vec.begin(),vec.end(),greater<int>());
        for(int j=0;j+1<vec.size();j++)
            ans[j]+=vec[j]-vec[j+1];
    }
    for(int i=0;i<=k;i++)
        write(ans[i]),putc('\n');
	flush();
}

标签:int,题解,P9041,namespace,Poly,Fiolki,inline,mod,define
From: https://www.cnblogs.com/cyffff/p/18374118

相关文章

  • 题解:P10881「KDOI-07」能量场
    \(\text{Link}\)题意给你一个长为\(n\)的序列\(a_{1\dotsn}\),定义一条边\((u,v)\)的权值为\(a_u+a_v\)。对于一张图,定义其权值为包含的所有边的权值乘积。求所有\(n\)个点的有标号基环树的权值之和。对\(998244353\)取模。\(n\le10^3\)。思路非常厉害的题,zky倾......
  • 题解:P10698 [SNCPC2024] 最大流
    \(\text{Link}\)题意给定一个\(n\)个点\(m\)条边的单位网络,保证该网络不存在环。给定一个常数\(k\),设从\(1\)到\(i\)的最大流为\(f_i\),对\(\foralli\in[2,n]\)求出\(\min(f_i,k)\)。\(n\le10^5\),\(m\le2\times10^5\),\(k\le\min(n-1,50)\)。思路不相交路径,考......
  • 升级Openssh 后 最大文件打开数修改不生效,启动 UsePAM yes后 ,最大文件打开数生效但是
    感谢 博主https://blog.csdn.net/Daphnisz/article/details/124040904vi /etc/pam.d/sshd(注意不是/etc/pam.d/sshd.pam)#%PAM-1.0auth required pam_sepermit.soauthsubstackpassword-authauthincludepostlogin#Usedwithpolkittoreauthor......
  • 常见问题解决 --- 为什么我们常常发现服务器没有管理的端口
    我们在扫描一台主机全端口,发现没有开放管理端口,比如windows远程桌面或者是linux的ssh登陆。我列举一下常见的原因。常规管理方式:1.管理口不是常见的3389和22端口,而改为了高位端口号,避免被人发现。2.在管理端口上加上了安全策略导致无法直接连接,比如私钥登陆方......
  • 题解:CF1986B Matrix Stabilization
    洛谷传送门题意一个\(n\timesm\)的矩阵,依次进行以下操作:从\((1,1)\)开始遍历矩阵,找到最小的\((i,j)\)满足\(a{i,j}\)的值严格大于其所有相邻(四联通)单元格的值,如果没有则退出将1操作找到的\(a_{i,j}-1\)返回1操作求最后的矩阵。思路模拟,我们按照题目所说,从......
  • 题解:P7020 [NWRRC2017] Boolean Satisfiability
    题目传送门题目大意给定一个由大小写字母(变量),|和~组成的布尔代数式,变量可以任意赋值为True或False。求对于给定的变量,有多少种赋值方案使得给定的代数式值为True。思路一个一个看,首先考虑|,先假设只有|,则当代数式中有一个变量为True时,代数式的值变为True。因为每一......
  • 题解:P9788 [ROIR 2020 Day2] 区域规划
    题目传送门思路首先我们看下数据范围,$n<=3000$,范围很小,所以暴力枚举。于是第一份代码出来了。#include<bits/stdc++.h>usingnamespacestd;ints,a,b,c,d,n,m;intmain(){ ios::sync_with_stdio(false); cin.tie(),cout.tie(); cin>>n>>m; for(a=1;a<=n;a++) {......
  • 题解:P9784 [ROIR 2020 Day1] 超速
    传送门思路我们设\(T\)为所花的总时间,\(d\)为超速多少。然后不难知道$T=\sum_{i=1}^{n}\frac{l_i}{v_i+d}$,所以我们实际上是要找到符合条件最小的\(d\)。再结合题目所说最高被罚款的金额最少,然后二分枚举答案即可。时间复杂度\(O(nq\log(m))\)。AC代码#include......
  • 题解:P10892 SDOI2024
    题解:P10892SDOI2024题目传送门题目思路通过阅读题面,我们可以看出,其实对于每一次纠结,如果交出了\(\frac{n-1}{2}\)只猫猫,则剩下的为\(\frac{n+1}{2}\)只猫猫;如果交出了\(\frac{n+1}{2}\)只猫猫,则剩下的为\(\frac{n-1}{2}\)只猫猫。为了使纠结的次数尽可能小,我们要交出......
  • 启动应用程序出现pspluginwkr.dll找不到问题解决
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个pspluginwkr.dll文件(挑选合适的版本文件)把......