1. 程式人生 > >【比賽】模考 2018.03.11 塞克斯斯

【比賽】模考 2018.03.11 塞克斯斯

script rip 根據 utc fontsize 右下角 一個數 包括 範圍

【問題描述】

塞克斯斯是六兄弟中的老六,他喜歡老大福斯特,他希望福斯特
高興。所以他要幫福斯特寫作業。作業如下:
給 n 個正方形,正方形有兩種:
A 型:平行於坐標軸,中心位於(x,y),邊長為偶數 a;
B 型:和坐標軸成 45 度夾角,中心位於(x,y),對角線長為偶數 d。
求這些正方形覆蓋的面積總大小。

【輸入格式】

第一行一個整數 n。
接下來 n 行每行描述一個正方形,共有一個字符和三個整數。如
果字符為 A 表示是 A 型正方形,接下來輸入 x,y 和 a。如果字符為 B
表示是 B 型正方形,接下來輸入 x,y 和 d。

【輸出格式】

一行一個實數表示答案,保留 2 位小數。

【樣例輸入】

8
A -7 10 4
B 3 10 8
A -6 6 6
A -2 5 8
B 3 -1 8
B -7 -4 8
A 3 9 2
B 8 6 6

【樣例輸出】

205.50

【樣例解釋】

技術分享圖片

【子任務】

數據保證|x|,|y|,a,d≤1000,且 a 和 d 一定為正偶數。
數據分為三個子任務。
子任務一:20 分,保證 n≤1000。
子任務二:30 分,保證 n≤200000,只有 A 型正方形。
子任務三:50 分,保證 n≤200000。

【正解】

因為坐標範圍很小,所以就想能不能枚舉格子統計面積
我們用點的坐標包括上它右上角的格子
對於A型矩形(正放的矩形),前綴和維護每個格子上被多少個矩形覆蓋。所以對於每個矩形,在矩形的左下角的格子權值加一,矩形的左上角的上面一個格子和矩形的右下角的右邊一個格子的權值各減一,矩形的右上角的右上角格子的權值加一。最後兩個循環以前綴和的方式掃描過去,每個格子上的權值就是它被多少個矩形覆蓋

對於B型矩形(斜放的矩形),一樣用前綴和,只不過用另一個數組記錄。並且我們把坐標系也斜過去,把斜過去之後的一單位長度定位原坐標系的\(\sqrt2\)長度,那麽我們就發現原坐標系裏的\((x,y)\)在新坐標系裏的坐標是\((x+y,x-y)\)(根據點到直線的距離公式直接求)。
最後統一掃描的時候,先掃描B的前綴和,再在掃描A的前綴和的時候統計答案。我們把每個格子拆成四個三角形。如果這個格子在A的前綴和中已經被覆蓋過了,那麽\(ans\)直接加4。否則找它斜過去後對應的B的前綴和中的四個格子,有多少格子被覆蓋,那麽\(ans\)加多少值
最後\(ans\)除4
(註意,因為B的坐標系的單位長度小,所以它的整個大小是A的坐標系的兩倍)

#include<bits/stdc++.h>
#define ll long long
const int Abs=1500+10,MAXN=Abs<<1;
int s1[MAXN][MAXN],s2[MAXN<<1][MAXN<<1],n;
double ans;
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char c='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(c!='\0')putchar(c);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
int main()
{
    freopen("skss.in","r",stdin);
    freopen("skss.out","w",stdout);
    read(n);
    for(register int i=1;i<=n;++i)
    {
        char opt;
        std::cin>>opt;
        if(opt=='A')
        {
            int x,y,a;
            read(x);read(y);read(a);
            x+=Abs,y+=Abs;
            s1[x-(a>>1)][y-(a>>1)]++;
            s1[x-(a>>1)][y+(a>>1)]--;
            s1[x+(a>>1)][y-(a>>1)]--;
            s1[x+(a>>1)][y+(a>>1)]++;
        }
        if(opt=='B')
        {
            int x,y,d;
            read(x);read(y);read(d);
            int nx=x+y+MAXN,ny=x-y+MAXN;
            s2[nx-(d>>1)][ny-(d>>1)]++;
            s2[nx-(d>>1)][ny+(d>>1)]--;
            s2[nx+(d>>1)][ny-(d>>1)]--;
            s2[nx+(d>>1)][ny+(d>>1)]++;
        }
    }
    for(register int i=1;i<(MAXN<<1);++i)
        for(register int j=1;j<(MAXN<<1);++j)s2[i][j]+=s2[i-1][j]+s2[i][j-1]-s2[i-1][j-1];
    for(register int i=1;i<MAXN;++i)
        for(register int j=1;j<MAXN;++j)
        {
            s1[i][j]+=s1[i-1][j]+s1[i][j-1]-s1[i-1][j-1];
            if(s1[i][j])
            {
                ans+=4.0;
                continue;
            }
            int nx=i+j,ny=i-j+MAXN;
            if(s2[nx][ny])ans++;
            if(s2[nx+1][ny])ans++;
            if(s2[nx][ny-1])ans++;
            if(s2[nx+1][ny-1])ans++;
        }
    ans/=4.0;
    printf("%.2f\n",ans);
    return 0;
}

【比賽】模考 2018.03.11 塞克斯斯