题解:Gym104479J Joining Arrays & 熙攘市场今何在

在艾斯比题上浪费一下午,真是神了。

显然先把集合排序,考虑先求出 \(b\)。对于 \(b_i\) 要使他最大,最优的肯定是 \(i\) 填他能填的最大值(假设是 \(x\)),对于所有 \(j\) 如果 \(S_{j,1}<x\),那么就把所有 \(S_{j,k}\ge x\) 删掉,因为一定不优。否则不管。

确定完 \(b\) 后,我们发现此时存在 \(\binom n2\) 个偏序关系,形如 \(a_i<a_j\),得知这个东西我们就可以将 \(a\) 排序。

但是我们很显然不能 \(\mathcal O(n^2)\) 两两去求偏序,但注意到 \(a\) 的偏序关系其实是和上面操作完的 \(S_{i,|S_i|}\)(即集合内的最大值)的偏序关系是一样的,所以直接对按照 \(S_{i,|S_i|}\) 的大小对 \(S\) 进行排序。

那问题转化成每一个集合里选一个数 \(a_i\),要求 \(a_i\) 单调递增。直接 dp 是容易的。

赛时这个sb就想到这里。sb大样例成功让我挂成滚木。

发现不同集合的数有可能重复,那我们刚刚的做法就G了。怎么解决这个问题?拆开相等的数就行了,强制让后面的相同数偏序前面的相同数,离散化可以简单实现。

int n,x,ans,len;
vector<int>a[500005],dp[500005]; 
pii p[500005];
void solve(){
	cin>>n;
	set<int>s;
	s.insert(2e9);
	fo(i,1,n){
		cin>>x,a[i].assign(x+1,0),a[i][0]=x;
		fo(j,1,x)cin>>a[i][j],p[++len]={a[i][j],i};
	}
	sort(p+1,p+1+len),len=unique(p+1,p+1+len)-p-1;
	fo(i,1,n){
		fo(j,1,a[i][0])a[i][j]=lower_bound(p+1,p+1+len,make_pair(a[i][j],i))-p;
		sort(a[i].begin()+1,a[i].begin()+1+a[i][0]);
		int mx=*s.lower_bound(a[i][1]);
		if(a[i][1]<mx)while(a[i][a[i][0]]>=mx)a[i][0]--;
		s.insert(a[i][a[i][0]]);
	}
	sort(a+1,a+1+n,[](auto p,auto q){return p[p[0]]<q[q[0]];});
	fo(i,1,n)
		if(i==1)dp[i].assign(a[i][0]+1,1);
		else{
			dp[i].assign(a[i][0]+1,0);
			int sum=0,l=0;
			fo(j,1,a[i][0]){
				while(l<a[i-1][0]&&a[i-1][l+1]<a[i][j])cplus(sum,dp[i-1][++l]);
				dp[i][j]=sum;
			}
		}
	fo(i,1,a[n][0])cplus(ans,dp[n][i]);
	cout<<ans;
}
posted @ 2026-08-22 16:46  qwertim  阅读(2)  评论(0)    收藏  举报