LOJ4222 「IOI2024」馬賽克上色 題解

peiwenjun發表於2024-09-11

題目描述

給定長為 \(n\) 、下標從零開始的 \(01\) 序列 \(x,y\) ,保證 \(x_0=y_0\)

\(col_{0,j}=x_j,col_{i,0}=y_i\) ,對 \(\forall 1\le i\lt n,1\le j\lt n\)\(col_{i,j}=[col_{i-1,j}=0\and col_{i,j-1}=0]\)

\(q\) 次詢問,給定 \(u,d,l,r\) ,求 \(\sum_{i=u}^d\sum_{j=l}^rcol_{i,j}\)

資料範圍

  • \(1\le n,q\le 2\cdot 10^5\)
  • \(0\le u\lt d\lt n,0\le l\lt r\lt n\)

時間限制 \(\texttt{1s}\) ,空間限制 \(\texttt{2048MB}\)

分析

先分析 \(col\) 矩陣的性質。

先暴力求出所有滿足 \(\min(i,j)\le 2\) 的位置(即前 \(3\)\(3\) 列)的值,容易發現:

  • 對於數列 \(col_{n-1,1}\cdots,col_{1,1},col_{1,n-1}\) ,不會有連續兩個 \(1\)

證明:

顯然。

  • 對於數列 \(col_{n-1,2},\cdots,col_{2,2},\cdots,col_{2,n-1}\) ,不會有連續兩個 \(1\) ,也不會有連續 \(3\)\(0\)

證明:

前半部分顯然,下面僅考慮後半部分。

\(col_{i+1,2}=col_{i,2}=col_{i-1,2}=0\) ,則 \(col_{i+1,1}=col_{i,1}=1\) ,矛盾。

\(col_{3,2}=col_{2,2}=col_{2,3}=0\) ,則 \(col_{3,1}=col_{1,3}=1\) ,且 \(col_{2,1}\)\(col_{1,2}\) 至少一個為 \(1\) ,矛盾。

\(col_{2,j-1}=col_{2,j}=col_{2,j+1}=0\) ,則 \(col_{1,j}=col_{1,j+1}=1\) ,矛盾。

綜上即可得證。

再考慮 \(i\ge 2,j\ge 2\) 時,每個 \(1\) "管轄" 的範圍。

它所在斜線一定為 \(1\) ,並且相鄰兩條斜線一定為 \(0\) ,如下圖所示:

image

透過上述性質我們可以按照斜線不重不漏確定整個矩陣,這是因為兩條相鄰的斜線 \(1\) 之間只能間隔 \(1\)\(2\) 條斜線 \(0\)


對詢問做二維差分,單獨處理前 \(2\)\(2\) 列,轉化為求 \(\sum_{i=2}^a\sum_{j=2}^b col_{i,j}\)

為方便起見,記 \(m=n-2,a\gets a-1,b\gets b-1\) ,令矩陣下標從 \(1\) 開始。

\(o_1,\cdots,o_{2m-1}\) 表示每條斜線的數值,對斜線出發點和穿過詢問矩形的邊界分類討論:

  • 出發點在左邊界,穿過矩形下邊界:貢獻 \(\sum(a+i-m)\cdot o_i\)
  • 出發點在左邊界,穿過矩形右邊界:貢獻 \(\sum b\cdot o_i\)
  • 出發點在上邊界,穿過矩形下邊界:貢獻 \(\sum a\cdot o_i\)
  • 出發點在上邊界,穿過矩形右邊界:貢獻 \(\sum(b+m-i)\cdot o_i\)

預處理 \(\sum o_i\)\(\sum i\cdot o_i\) 即可做到 \(\mathcal O(1)\) 回答,注意經過左上角和右下角的斜線不要算重。

時間複雜度 \(\mathcal O(n+q)\)

#include<bits/stdc++.h>
#include"mosaic.h"
#define ll long long
#define vi vector<int>
using namespace std;
const int maxn=2e5+5;
int m;
int o[2*maxn],s1[maxn],s2[maxn],s3[maxn],s4[maxn];
ll t1[2*maxn],t2[2*maxn];
vi col[maxn];
ll get(int l,int r,int x,int y)
{///\sum_{i=l}^r(x+y*i)*o[i]
    return l<=r?x*(t1[r]-t1[l-1])+y*(t2[r]-t2[l-1]):0;
}
ll calc(int a,int b)
{
    if(min(a,b)<0) return 0;
    ll res=0;
    for(int i=0;i<=1;i++)
        for(int j=0;j<=1;j++)
            if(i<=a&&j<=b) res+=col[i][j];
    if(a>=0) res+=s1[b];
    if(a>=1) res+=s2[b];
    if(b>=0) res+=s3[a];
    if(b>=1) res+=s4[a];
    if(--a>=1&&--b>=1)
    {
        res+=get(m+1-a,min(m,b-a+m),a-m,1);
        res+=get(b-a+m+1,m,b,0);
        res+=get(m+1,b-a+m,a,0);
        res+=get(max(m+1,b-a+m+1),m+b-1,b+m,-1);
    }
    return res;
}
vector<ll> mosaic(vi x,vi y,vi u,vi d,vi l,vi r)
{
    int n=x.size(),q=u.size();
    for(int i=0;i<n;i++)
    {
        col[i].resize(i<3?n:3);
        for(int j=0;j<col[i].size();j++)
        {
            if(!i) col[i][j]=x[j];
            else if(!j) col[i][j]=y[i];
            else col[i][j]=!col[i-1][j]&!col[i][j-1];
        }
    }
    for(int i=2;i<n;i++) s1[i]=s1[i-1]+col[0][i],s2[i]=s2[i-1]+col[1][i];
    for(int j=2;j<n;j++) s3[j]=s3[j-1]+col[j][0],s4[j]=s4[j-1]+col[j][1];
    m=n-2;
    for(int j=1;j<=2*m-1;j++)
    {
        o[j]=j<=m?col[m+2-j][2]:col[2][j-m+2];
        t1[j]=t1[j-1]+o[j],t2[j]=t2[j-1]+o[j]*j;
    }
    vector<ll> vec(q);
    for(int i=0;i<q;i++)
        vec[i]=calc(d[i],r[i])-calc(u[i]-1,r[i])-calc(d[i],l[i]-1)+calc(u[i]-1,l[i]-1);
    return vec;
}

相關文章