CF 1606 D題題解
阿新 • • 發佈:2021-10-30
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\)列和後\(m-k\)列,分開考慮如何選取一些行塗成紅色。容易看出左邊一定是按行最小值從大到小排序,依次選擇;右邊則是按行最大值升序排序,依次選擇。當兩邊選擇的行的集合完全重合時,這樣的劃分就有可能成為一種合法方案(即一個必要條件)。將所有這樣的集合\(S\)存到一個map裡。
再重複這個過程去選塗成藍色的行。將所有集合\(T\)存到另一個map裡。
如果存在一個\(S\)和一個\(T\)使得\(S\)和\(T\)的並集為全集-----那麼離合法方案僅差一步:
至此我們只得到了一個完整的劃分,但並不能保證這樣的劃分\(S,T\)
在\(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; }