题解: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;
}

浙公网安备 33010602011771号