CF2035G. Go Learn!

怎么有人老喜欢在讲课的题里塞 3500 啊,发怒。

题目链接:G2 - Go Learn!

题目大意:对于一个点对 \((x,t)\),我们认为数组 \(a\)(可能无序) 合法当且仅当 \(\text{lower_bound(a,x)=t}\)。(具体见题面二分查找代码)给定大小为 \(m\) 的点对集合 \(S=\{(x,k)\}\),保证 \(x_i\)\(k_i\) 分别互不相同,你需要:

  • 找到 \(S'\subseteq S\),使得存在一个长度为 \(n\),值域为 \([1,n]\) 的数组 \(a\),其对 \(S'\) 中的所有点对都合法。最大化 \(|S'|\)
  • 设上一问答案为 \(\text{Ans}\),求出长度为 \(n\),值域为 \([1,n]\) 的数组 \(a\) 的个数,使得存在一个大小为 \(\text{Ans}\) 的集合 \(S'\subseteq S\),满足 \(a\)\(S'\) 中的所有点对都合法。对 \(\text{998244353}\) 取模

Easy Version:\(1\leq m\leq n\leq 3000,\sum n\leq 10^4\)

Hard Version:\(1\leq m\leq n\leq 3\times 10^5,\sum n\leq 10^6\)


首先考虑第一问,我们需要分析一个点对如何才能合法。根据二分的过程,可以建出类似线段树的结构,每个点对相当于对叶子到根结点的一条路径有限制。

这里可以发现只要 \(k\neq 1\) 就一定可以在任意节点上填入符合条件的值。否则在 \(k=1\) 的情况下 \(x\) 必须为 \(1\)

此外,可以发现,若出现了 \(x_i<x_j,k_i>k_j\) 的情况,那么两个限制就会在他们的 LCA 处产生冲突。所以将点对按 \(x_i\) 升序排序,第一问的答案就是 LIS。

接下来考虑第二问,我们设 \(f_i=(x,y)\) 表示到位置 \(i\) 为止,且位置 \(i\) 的点对 \((i,p_i)\) 被选择的情况下,LIS 的长度为 \(x\),且到目前合法的 \(a\) 数组有 \(y\) 种方案。转移时考虑上一个被选的位置 \(j\),LIS 长度方面的转移是显然的,方案数上则是有 \(W(j,i)\times f_j.y\) 的转移。其中 \(W(j,i)\) 表示从 \(j\) 扩展到 \(i\) 时,依次确定 \(A_{[j,i]}\) 的值的方案数。

思考怎么算出这个转移系数,我们令 \(path(i)\) 为二分的过程中,确定 \(i\) 位置的数的过程中经过的点的集合。这里也不难发现所谓限制就是 \(path(i)\) 中比 \(i\) 左边的数的值要 \(<p_i\),比 \(i\) 右边的数的值要 \(\ge p_i\)。设在区间 \((j,i)\) 中:

  • 同时属于 \(path(j)\)\(path(i)\) 的数有 \(b\) 个,他们的取值 \(p_j\le v\lt p_i\)
  • 只属于 \(path(j)\) 的有 \(L\) 个,他们的取值 \(v\ge p_j\)
  • 只属于 \(path(i)\) 的有 \(R\) 个,他们的取值 \(v\lt p_i\)

那么有 \(W(j,i)=n^{i-j-1-b-L-R}(p_i-p_j)^b(n-p_j+1)^L(p_i-1)^R\)。预处理 \(path(i)\) 之后,暴力就可通过 Easy Version。

接下来考虑优化,很难不发现 \(b=1\),且对应点的位置就是 \(j\)\(i\) 的 LCA。设这个点的位置为 \(m\),那么 \(L\) 的值就是区间 \((j,m)\) 内在 \(path(j)\) 上的点数,\(R\) 的值就是区间 \((m,i)\) 内在 \(path(i)\) 上的点数。

于是在DP的时候,只需枚举 \(m\) 的值,并将所有 \(j\) 相关的贡献提前放在 LCA 上。也就是在算出每个 \(j\) 之后,在 \(path(j)\) 中比 \(j\) 右边的点存储进这些贡献,然后在计算 \(i\) 的时候,枚举 \(i\) 左边的 \(path(i)\) 上的点转移。这里需要考虑 \(j\) 就是 LCA 的情况,在 \(i\) 处枚举 \(path(i)\) 上的点时额外讨论即可。

为了让 DP 计算过程合法,我们直接枚举从小到大枚举 \(k\) 的值,插入相关点对并更新 DP 值,这样就能做到 \(O(m\log ^2n)\) 的复杂度。

在前缀和优化的具体实现上还是需要仔细推一推的,最后可以发现把 \(n\) 相关系数扔到外面算会比较好算一些,详见代码实现及注释。

注释里的式子其实漏算了 \(n\) 的指数里的 \(-b\),这就是为什么转移时还要补一个 \(n\) 的逆元。

#include<bits/stdc++.h>
using namespace std;
#define N 300030
#define LL long long
#define MOD 998244353
int T,n,m,x,k,p[N],q[N];
vector<int>pre[N],nxt[N];
struct rua
{
	int x,y;
	rua operator +(const rua &t)const{
		if(x<t.x)return t;
		if(x>t.x)return *this;
		return (rua){x,(y+t.y)%MOD};
	}
	rua operator -(const rua &t)const{return (rua){x,(y+MOD-t.y)%MOD};}
	rua operator *(const int &t)const{return (rua){x,1ll*y*t%MOD};}
}f[N],s[N],S[N],ans;
LL qow(LL x,LL y){return y?(y&1?x*qow(x,y-1)%MOD:qow(x*x%MOD,y/2)):1;}
void init()
{
	ans=(rua){0,1};
	scanf("%d%d",&n,&m);
	int in=qow(n,MOD-2);
	for(int i=1;i<=n;i++){
		p[i]=q[i]=0;
		nxt[i].clear();
		pre[i].clear();
		f[i]=s[i]=S[i]=(rua){-1,1};
		int l=1,r=n,mid;
		while(l<r){
			mid=l+r>>1;
			if(i<=mid){
				if(i<mid)nxt[i].push_back(mid);
				r=mid;
			}
			else{
				pre[i].push_back(mid);
				l=mid+1;
			}
		}
		sort(nxt[i].begin(),nxt[i].end());
		sort(pre[i].begin(),pre[i].end());
		reverse(pre[i].begin(),pre[i].end());
	}
	for(int i=1;i<=m;i++){
		scanf("%d%d",&x,&k);
		if(x>1 && k==1)continue;
		p[x]=k,q[k]=x;
	}
	//f[i]=f[j]*(p[i]-p[j])*(n-p[j]+1)^L*(p[i]-1)^R*n^(i-j-1-L-R)
	//f[i]=f[j]*(n-p[j]+1)^L*(p[i]-p[j])*(p[i]-1)^R*n^(m-j-L)*n^(i-m-R-1)
	//f[i]=n^(m-j)*f[j]*((n-p[j]+1)/n)^L * n^(i-m-1)*p[i]*((p[i]-1)/n)^R  -  n^(m-j)*f[j]*((n-p[j]+1)/n)^L*p[j] * n^(i-m-1)*((p[i]-1)/n)^R
	//f[i]= s[m]*p[i]*pR-S[m]*pR
	
	//f[i]=f[m]*(p[i]-1)^R*n^(i-m-1-R)=f[m]*pR
	for(int k=1;k<=n;k++)if(q[k]){
		int i=q[k],pL=1,pR=1,b=1ll*(p[i]-1)*in%MOD;
		for(auto m:pre[i]){
			f[i]=f[i]+(s[m]*p[i]-S[m])*pR*in;
			if(p[m])f[i]=f[i]+f[m]*pR;//m=j
			pR=1ll*pR*b%MOD;
		}
		f[i]=f[i]+(rua){0,pR};// Start
		f[i].x++;
		
		b=1ll*(n-p[i]+1)*in%MOD;
		for(auto m:nxt[i]){
			s[m]=s[m]+f[i]*pL;
			S[m]=S[m]+f[i]*p[i]*pL;
			pL=1ll*pL*b%MOD;
		}
		ans=ans+f[i]*pL;// End
	}
	printf("%d %lld\n",m-ans.x,qow(n,n-ans.x)*ans.y%MOD);
}
int main()
{
	scanf("%d",&T);
	while(T--)init();
}
posted @ 2026-07-30 04:23  DeaphetS  阅读(2)  评论(0)    收藏  举报