CF 1606 D题题解
CF 1606 D题题解
题意:给定\(n*m\)的矩阵\(A=a_{i,j}\),需要给每一行染上红色或者蓝色,使得存在一个划分\(k\) (\(1 \leq k \leq m-1\)) 将m列分为左右两块,使得:
1.左边矩阵中颜色为红色的\(a\)的最小值大于颜色为蓝色的\(a\)的最大值;
2.右边矩阵中颜色为蓝色的\(a\)的最小值大于颜色为红色的\(a\)的最大值。
若存在合法方案,输出染色情况和\(k\);若不存在,输出"NO"。若存在多解,可输出任意一个。
多组数据,\(n \times m \leq 5 \times 10^5\)
题解:首先确定时间复杂度一定是\(O(nmlog^kn)\)。枚举\(k\),然后用\(O(nlogn)\)的复杂度判断合法性。
将矩阵分为前\(k\)列和后\(m-k\)列,分开考虑如何选取一些行涂成红色。容易看出左边一定是按行最小值从大到小排序,依次选择;右边则是按行最大值升序排序,依次选择。当两边选择的行的集合完全重合时,这样的划分就有可能成为一种合法方案(即一个必要条件)。将所有这样的集合\(S\)存到一个map里。
再重复这个过程去选涂成蓝色的行。将所有集合\(T\)存到另一个map里。
如果存在一个\(S\)和一个\(T\)使得\(S\)和\(T\)的并集为全集-----那么离合法方案仅差一步:
至此我们只得到了一个完整的划分,但并不能保证这样的划分\(S,T\)满足条件。这时候就体现出分别做两次的优势了:我们在将\(S\)和\(T\)加入map时,同时可以存下左边和右边的某颜色的最值,这样就能方便比较了。
在\(O(n)\)的复杂度内求出\(k\)确定时每一行左右两边的最值是oier应具备的基本素质,这里不再细说。
时间复杂度:\(O(nmlogn)\)。
代码:
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
typedef __int128 i128;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
#define Debug(x,y) F(i,1,y)cout<<x[i]<<" ";cout<<endl;
template<class D>I read(D &res){
res=0;re g=1;register char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
typedef pair<int,int>pii;
const int Mod=998244353,INF=1e7;
int n,m,T,X,Y,wx,wy,sn,vis[505000],t[505000],mx[505000],mn[505000],xm[505000],nm[505000];
map<int,pii>mp;map<int,int>to;
priority_queue<pii>px;
priority_queue<pii,vector<pii>,greater<pii> >py;
vector<int>v[505000],up[505000],dn[505000];
int main(){
t[0]=1;
F(i,1,500001)t[i]=(t[i-1]<<1)%Mod,to[t[i]]=i;
read(T);
while(T--){
read(n);read(m);sn=0;
F(i,1,n){
vis[i]=0;
v[i].resize(m+1);up[i].resize(m+1);dn[i].resize(m+1);
F(j,1,m)read(v[i][j]);
re maxi=v[i][m],mini=v[i][m];up[i][m]=dn[i][m]=m;
FOR(j,m-1,1){
if(v[i][j]>maxi)up[i][j]=j,maxi=v[i][j];
else up[i][j]=up[i][j+1];
if(v[i][j]<mini)dn[i][j]=j,mini=v[i][j];
else dn[i][j]=dn[i][j+1];
}
xm[i]=maxi;nm[i]=mini;
}
F(i,1,n)mx[i]=-INF,mn[i]=INF;
F(j,1,m-1){
mp.clear();X=Y=0;
while(!px.empty())px.pop();
while(!py.empty())py.pop();
F(i,1,n){
if(v[i][j]>mx[i])mx[i]=v[i][j];
if(v[i][j]<mn[i])mn[i]=v[i][j];
if(up[i][j]==j)xm[i]=v[i][up[i][j+1]];
if(dn[i][j]==j)nm[i]=v[i][dn[i][j+1]];
//cout<<mx[i]<<" "<<mn[i]<<" "<<xm[i]<<" "<<nm[i]<<endl;
px.push(make_pair(mn[i],t[i]));
py.push(make_pair(xm[i],t[i]));
}
F(i,1,n-1){
wx=px.top().first;(X+=px.top().second)%=Mod;px.pop();
wy=py.top().first;(Y+=py.top().second)%=Mod;py.pop();
//cout<<X<<" "<<Y<<endl;
if(wx>px.top().first&&wy<py.top().first&&X==Y)mp[X]=make_pair(wx,wy);
}
//cout<<"Check"<<endl;
X=Y=(t[n+1]+Mod-2)%Mod;
while(!px.empty())px.pop();while(!py.empty())py.pop();
F(i,1,n)px.push(make_pair(nm[i],t[i])),py.push(make_pair(mx[i],t[i]));
F(i,1,n-1){
wx=py.top().first;(X+=Mod-py.top().second)%=Mod;py.pop();
wy=px.top().first;(Y+=Mod-px.top().second)%=Mod;px.pop();
//cout<<X<<" "<<Y<<endl;
if(wx<py.top().first&&wy>px.top().first&&X==Y&&mp.find(X)!=mp.end()&&wx<mp[X].first&&wy>mp[X].second){
sn=1;cout<<"YES"<<endl;
while(!py.empty())vis[to[py.top().second]]=1,py.pop();
F(k,1,n){
if(vis[k])putchar('R');
else putchar('B');
}
cout<<" "<<j<<endl;
break;
}
}
//cout<<"End"<<endl;
if(sn)break;
}
/*if(!sn){
re j=m;
mp.clear();X=0;Y=(t[n+1]+Mod-2)%Mod;
F(i,1,n){
if(v[i][j]>mx[i])mx[i]=v[i][j];
if(v[i][j]<mn[i])mn[i]=v[i][j];
px.push(make_pair(mn[i],t[i]));
py.push(make_pair(mx[i],t[i]));
}
F(i,1,n-1){
wx=px.top().first;(X+=px.top().second)%=Mod;px.pop();
mp[X]++;
}
F(i,1,n-1){
wy=py.top().first;(Y+=Mod-py.top().second)%=Mod;py.pop();
if(mp[Y]){
sn=1;cout<<"YES"<<endl;
while(!py.empty())vis[to[py.top().second]]=1,py.pop();
F(k,1,n){
if(vis[k])putchar('R');
else putchar('B');
}
cout<<" "<<j<<endl;
break;
}
}
}*/
if(!sn)cout<<"NO"<<endl;
}
return 0;
}