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

posted @ 2021-10-30 12:10  Purple_wzy  阅读(73)  评论(0编辑  收藏  举报