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;
}

posted @ 2026-06-08 18:58  programmingysx  阅读(10)  评论(0)    收藏  举报
Title