[USACO20DEC] Rectangular Pasture S
阿新 • • 發佈:2021-12-25
不需 \(\operatorname{Discretization}\&\operatorname{BIT}\) 並且時間複雜度優秀的一篇題解!
本篇題解是對 這篇題解 的補充。
題目大意
網格圖上有 \(N\) 頭奶牛,第 \(i\) 頭奶牛座標為 \((x_i,y_i)\)。
現在用一個大小至少為 \(1\) 的矩形覆蓋若干格子,問被覆蓋的區域包含的奶牛集合有多少種情況,包含空集。(矩形恰好完整覆蓋若干格子)
題目分析
我們沒必要將邊界放在空格上。
我們首先對所有座標按照行從小到大排序。之後所有的牛都按照這個順序來操作。
設 \(y[i]\) 表示第 \(i\) 頭牛的列,\(l[j]\)
因為我們需要求出包含的奶牛集合有多少種情況 ,所以我們不妨討論第 \(i\) 頭奶牛作為下方邊界,第 \(j\) 頭奶牛作為上方邊界。
這樣子,我們就將題目簡化了。接下來分情況討論:
-
第 \(j\) 頭牛在第 \(i\) 頭牛的左邊時:
- 當第 \(k\) 行的牛在第 \(i\) 行的牛在第 \(j\) 頭牛之間且在第 \(j\) 頭牛左邊,即 \(i\lt k\lt j,y[k]\lt y[j]\)
\(k\) 一定可以作為當前框定的左邊界,當前情況的方案數為 \((rnum+1)\times(l[j]+1)\)。
\(rnum\) 表示第 \(i\) 行的牛與當前第 \(j\) 行的牛之間,有多少頭牛在第 \(i\) 行的牛右邊。加 \(1\) 是因為可以選擇邊界。
- 當第 \(k\) 行的牛在第 \(i\) 行的牛在第 \(j\) 頭牛之間且在第 \(i\) 頭牛右邊,即 \(i\lt k\lt j,y[k]\gt y[i]\) 時:
\(k\) 一定可以作為當前框定的右邊界,當前情況的方案數為 \((lnum+1)\times(r[j]+1)\)。
\(lnum\) 表示第 \(i\)
- 當第 \(k\) 行的牛在第 \(i\) 行的牛在第 \(j\) 頭牛之間且在第 \(j\) 頭牛左邊,即 \(i\lt k\lt j,y[k]\lt y[j]\)
-
第 \(j\) 頭牛在第 \(i\) 頭牛的右邊時同理。
時間複雜度 \(\mathcal{O}(n^2)\)。
程式碼
#define int long long
const int ma=2505;
struct Node
{
int x;
int y;
};
Node node[ma];
int l[ma],r[ma];
//l[j]:排序後,第 j 行的牛與當前第 i 行的牛之間,有多少頭牛在第 j 行的牛的左邊
//r[j]:排序後,第 j 行的牛與當前第 i 行的牛之間,有多少頭牛在當前第 i 行的牛的右邊
int n;
inline bool cmp(Node x,Node y)
{
if(x.x!=y.x)
{
return x.x<y.x;
}
return x.y<y.y;
}
#undef int
int main(void)
{
#define int long long
n=read();
for(register int i=1;i<=n;i++)
{
node[i].x=read(),node[i].y=read();
}
sort(node+1,node+n+1,cmp);
int ans=1;
for(register int i=1;i<=n;i++)
{
ans++;
int lnum=0,rnum=0;
for(register int j=i-1;j>=1;j--)
{
if(node[i].y>node[j].y)
{
ans+=(rnum+1)*(l[j]+1);
lnum++,r[j]++;
}
else
{
ans+=(lnum+1)*(r[j]+1);
rnum++,l[j]++;
}
}
}
printf("%lld\n",ans);
return 0;
}