20260602模拟赛
20260602模拟赛
没有名字的T3 LGV
题面:
你有 \(n\) 个点,编号为 \(1\) 到 \(n\),其中编号在 \([1, k]\) 的点为关键点。
关键点到非关键点,和非关键点到非关键点会有一些有向边,共 \(m\) 条。
保证构成的是有向无环图,无重边。
定义一组不交叉配为集合 \(A\) 与集合 \(B\) 每个点一一对应,\(A_i\) 对应 \(B_i\),所有 \(A_i\) 有路径到达 \(B_i\),并且存在一组路径方案,使得不存在 \(A_i\) 到 \(B_i\) 和 \(A_j\) 到 \(B_j\) 的路径有公共交点。(\(i \ne j\))不交叉配的大小就是 \(|A|\),也等价于 \(|B|\)。
设 \(f(l, r)\) 表示,所有满足 \(A\) 是关键点集合子集,\(B\) 是编号在 \([l, r]\) 非关键点集合子集的不交叉配的最大匹配大小。
需要你对于每个 \(i (0 \leq i \leq k)\) 求出 \(c_i = \sum_{k+1 \leq l \leq r \leq n} [f(l, r) = i]\)。
\(2\leq n\leq 10^5,1\leq m\leq 10^6,1\leq k\leq 50,k<n\)
题解:
考虑如何判断 \(k\) 对点有没有不交路径匹配,使用 LGV,每条边随机赋权,求出每个起终点之间的带权路径数 \(w(x,y)\),判断行列式是否为零即可。
那么考虑怎么求 \(f(l,r)\),它等于把每个 \(i(1\leq i\leq k)\) 到 \(j(l\leq j\leq r)\) 的 \(w(i,j)\) 看作 \(j\) 的一个向量,那么 \(f(l,r)\) 等于这 \((r-l+1)\) 个向量的极大线性无关子集。因为如果存在集合 \(S\subseteq\{1,\cdots,k\},T\subseteq\{l,\cdots,r\},|S|=|T|\) 有不交路径匹配就等价于,所有 \(x\in S,y\in T,w(x,y)\) 形成的矩阵行列式不为零,等价于 \(T\) 的秩等于 \(|T|\)。
那么这就容易通过前缀线性基对于每个 \(r,k\) 维护出 \(f(l,r)=k\) 的 \(l\) 的区间,复杂度 \(O(nk^2)\)。
代码
#include<bits/stdc++.h>
#define ll long long
#define fir first
#define sec second
using namespace std;
inline int read(){
int s=0,k=1;
char c=getchar();
while(c>'9'||c<'0'){
if(c=='-') k=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
s=(s<<3)+(s<<1)+(c^48);
c=getchar();
}
return s*k;
}
mt19937 rnd(time(0));
const int N=1e5+5,M=52,mod=1e9+7;
int n,m,K,ids[M],ind[N];
ll ans[M];
vector<pair<int,ll> >e[N];
struct VEC{
ll v[M];
ll& operator[](int i){return v[i];}
}f[N],a[M];
ll Mod(ll x){return x>=mod?x-mod:x;}
ll ksm(ll a,ll b){
ll t=1;
for(;b;b>>=1,a=a*a%mod)
if(b&1) t=t*a%mod;
return t;
}
void insert(int id,VEC x){
for(int i=1;i<=K;i++)
if(x[i]){
if(!ids[i]){
ids[i]=id;
a[i]=x;
break;
}
if(id>ids[i]){
swap(id,ids[i]);
swap(x,a[i]);
}
ll inc=ksm(a[i][i],mod-2);
for(int j=i;j<=K;j++) (a[i][j]*=inc)%=mod;
for(int j=K;j>=i;j--)
x[j]=Mod(x[j]+mod-x[i]*a[i][j]%mod);
}
}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n=read();m=read();K=read();
for(int i=1;i<=m;i++){
int u=read(),v=read();
ll w=rnd()%(mod-1)+1;
e[u].emplace_back(v,w);
ind[v]++;
}
for(int i=1;i<=K;i++) f[i][i]=1;
queue<int>q;
for(int i=1;i<=n;i++)
if(ind[i]==0) q.push(i);
while(!q.empty()){
int x=q.front();
q.pop();
for(pair<int,ll> o:e[x]){
int v;ll w;
tie(v,w)=o;
for(int i=1;i<=K;i++) (f[v][i]+=f[x][i]*w)%=mod;
ind[v]--;
if(ind[v]==0) q.push(v);
}
}
for(int i=K+1;i<=n;i++){
insert(i,f[i]);
vector<int>vec({i,K});
for(int j=1;j<=K;j++)
if(ids[j]) vec.push_back(ids[j]);
sort(vec.begin(),vec.end(),greater<int>());
for(int i=1,c=0;i<vec.size();i++,c++)
ans[c]+=vec[i-1]-vec[i];
}
for(int i=0;i<=K;i++) printf("%lld\n",ans[i]);
return 0;
}

浙公网安备 33010602011771号