CF 1980 F1 Field Division (easy version) (*1900)

Showball發表於2024-06-17

CF 1980 F1 Field Division (easy version) (*1900)

題目連結

題意

有一個大小為 \(n \times m\) ($2 \le n,m\le 10^9 $)的矩形。其中有 \(k\) 個噴泉,你現在可以從左側或者上側任意一個不是噴泉的單元格出發,每次只能移向相鄰的下或者右的單元格。直到走到矩陣的右側或者底側結束。並且中途不能經過任何一個噴泉。走過的路徑將整個矩陣分成了兩個部分。請你求出左下這一部分的面積最大值(包含走過的單元格)。並且回答對於每個噴泉,如果允許經過,面積是否會增大。

思路

顯然,我們每次都貼著噴泉去走,面積才會最大。我們可以把面積根據噴泉的位置劃分成一段一段來求解。

容易發現只有後面的噴泉的橫座標大於前面的橫座標才會拐彎。那麼我們可以維護每一列的最大橫座標。

按照縱座標順序列舉所有噴泉的縱座標計算即可。因為範圍很大,那麼用map維護即可。

接著看第二個問題,我們發現只有滿足當前噴泉的橫座標是當前列的橫座標最大值並且大於前一個噴泉對應的

最大橫座標即可。這裡開了一個st陣列來維護前一個噴泉對應的最大橫座標。

程式碼

#include<bits/stdc++.h>

using namespace std;

#define ff first
#define ss second
#define pb push_back
#define all(u) u.begin(), u.end()
#define endl '\n'
#define debug(x) cout<<#x<<":"<<x<<endl;

typedef pair<int, int> PII;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 10, M = 105;
const int mod = 1e9 + 7;
const int cases = 1;

void Showball(){
   int n,m,k;
   cin>>n>>m>>k;
   vector<PII> a(k+1);
   map<int,int> rmax;
   vector<int> col;
   for(int i=1;i<=k;i++){
      int x,y;
      cin>>x>>y;
      a[i]={x,y};
      col.pb(y);
      rmax[y]=max(rmax[y],x);
   }
   sort(all(col));
   int len=unique(all(col))-col.begin();
   LL ans=0;
   int cur=0;
   map<int,int> st;
   int pre=1;
   for(int i=0;i<len;i++){
      int y=col[i];
      ans+=1LL*(y-pre)*(n-cur);
      st[y]=cur;
      cur=max(cur,rmax[y]);
      pre=y;
   }
   ans+=1LL*(m-pre+1)*(n-cur);
   cout<<ans<<endl;
   for(int i=1;i<=k;i++){
      auto [x,y]=a[i];
      if(x==rmax[y]&&x>st[y]) cout<<"1 ";
      else cout<<"0 ";
   }
   cout<<endl;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int T=1;
    if(cases) cin>>T;
    while(T--)
    Showball();
    return 0;
}

相關文章