1. 程式人生 > 其它 >CF 1606 D題題解

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