11年上海賽區賽真題 Bombing

11年上海賽區賽真題 Bombing


該題考查數據離散處理能力,求點的座標的情況。

0 x,去掉橫座標爲x的那一行上的所有點

1 y,去掉縱座標爲y的那一列上的所有點

輸出每次給出的條件去掉的點的個數。


表示這個題弄了很久,一直超時,也很煩躁。後面參考了別人的想法,才覺得,這個題,是一個內涵題。想做出來,要麼STL用的淋漓盡致,要麼有足夠的聰慧,又要敢於暴力。


該題在網絡上常見的解法有兩種,我借鑑了思想,自己寫了。對於STL的解法,代碼短小精悍,各種容器,各種鑲嵌,各種插入刪除,對我這個STL剛入門的菜鳥來說,簡直就是“太神奇了”。STL解法含金量極高,對於普通解法,是1行頂2行,甚至是3行,我稱之爲【高端霸氣上檔次】。而另一種解法,要敢於用內存,敢於暴力,有要有智慧,排序加二分,剛柔並濟。用最淳樸的思想,解決了各種“離散型”數據的問題,我稱之爲【低調奢華有內涵】


對於STL的解法:【高端霸氣上檔次】

以最易於理解的邏輯解題,用到容器map和multiset(同一個點上可能不止一個據點)。

主要分爲以x爲關鍵字的mapx和以y爲關鍵字的mapy,其中有嵌套的set,具體的數據結構是:

mapx<int,multiset<int> >(兩個>號中間有空格) 【 int型的關鍵字】存儲橫座標,set中存儲所有橫座標爲【int關鍵字】的點的縱座標。

同理可得mapyM<int ,multiset<int> >

查找時,找到相應的關鍵字,提取其set中元素的個數,然後將另一map容器中與這些點對於的信息刪除,並情況該map該關鍵字的set容器即可


對於排序二分的解法:【低調奢華有內涵】

將輸入的座標,按輸入的順序每個座標賦予一個序號。同時存在兩個數組中arrx(以x值爲關鍵字排序檢索)和數組arry中(以y值爲關鍵字排序檢索)。同時有一個數組flag,flag[i]中的值記錄序號爲i的點的訪問情況,訪問過的標爲“true”,未訪問過的標記爲“false”。

對於所有輸入的點的信息,將座標存入相關數據結構中。輸入詢問後,先用二分搜索,找到相關關鍵字數組中第一次出現詢問關鍵字的數組下標。從該下標開始查詢,直到關鍵字不同或數組尾時結束查詢。對於每個查詢,如若該點沒訪問過(flag標記數組),則計數並標記爲訪問。否則,直接跳過。

對於每次詢問,輸出計數變量的值(初始化爲0)即可。


【高端霸氣上檔次】

#include<cstdio>
#include<iostream>
#include<map>
#include<set>
using namespace std;
int main()
{
    int n,m;
    int x,y;
    int ans;
    multiset<int>::iterator it;   //multiset的迭代器
    while(scanf("%d%d",&n,&m)&&n+m)
    {
        map<int,multiset<int> > mapx,mapy;   //X,Y爲關鍵字的容器
        while(n--) //n組值
        {
            scanf("%d%d",&x,&y);
            mapx[x].insert(y);  //x軸的x爲關鍵字,與其關聯的Y都存儲在其“值”set<int>中,利於查找
            mapy[y].insert(x);  //y軸的y爲關鍵字,與其關聯的x都存儲在其“值”set<int>中,利於查找
        }
        while(m--)  //對於m組查找數據
        {
            scanf("%d%d",&x,&y);
            if(!x)  //查找,以x值爲關鍵字
            {
                ans=mapx[y].size();  //提取與x軸值爲y的關鍵字有關聯的,尚未處理的點的情況(數量)
                for(it=mapx[y].begin();it!=mapx[y].end();it++)//對該x=y的值所對的點進行刪除
                    mapy[*it].erase(y);  //刪除該點在y關鍵字容器中的相關值
                mapx[y].clear();   //清空x=y的點的數據(炸掉了)
            }
            else   //查找,以y值爲關鍵字(同上)
            {
                ans=mapy[y].size();
                for(it=mapy[y].begin();it!=mapy[y].end();it++)
                    mapx[*it].erase(y);
                mapy[y].clear();
            }
            printf("%d\n",ans);  //輸出結果
        }
        printf("\n");  //每組測試數據後面輸出一個空行
    }
    return 0;
}


【低調奢華有內涵】

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
struct node
{
    int x;
    int y;
    int f;
}arrx[100002],arry[100002];   //每個點的信息,座標及其序號(輸入時的序號)
bool flag[100002];   //記錄相關序號的點是否被訪問過,訪問過標爲“true”,否則標爲“false”
int n,m;
bool cmpx(node a,node b)  //按x從小到大排序
{
    return a.x<b.x;
}
bool cmpy(node a,node b)  //按y從小到大排序
{
    return a.y<b.y;
}
int findx(int x)  //二分法查找第一個x與給定x相等的座標的結構體數組下標
{
    int l=0,r=n-1,mi;
    while(l<r)
    {
        mi=(l+r)/2;
        if(arrx[mi].x>=x)r=mi;
        else l=mi+1;
    }
    return l;
}
int findy(int y)  //二分法查找第一個y與給定y相等的座標的結構體數組下標
{
    int l=0,r=n,mi;
    while(l<r)
    {
        mi=(l+r)/2;
        if(arry[mi].y>=y)r=mi;
        else l=mi+1;
    }
    return l;
}
int main()
{
    int x,y;
    int i,j;
    while(scanf("%d%d",&n,&m)&&n+m)
    {
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            arrx[i].x=x,arrx[i].y=y,arrx[i].f=i;  //初始化x值查詢數組的信息
            arry[i].x=x,arry[i].y=y,arry[i].f=i;  //初始化y值查詢數組的信息
            flag[i]=false;  //初始化訪問標記變量(都未訪問)
        }
        sort(arrx,arrx+n,cmpx);  //x值查詢數組以x爲標準排序,利於二分查找
        sort(arry,arry+n,cmpy);
        while(m--)   //m組詢問
        {
            int sum=0;
            scanf("%d%d",&x,&y);
            if(!x)  //查詢以x爲基準
            {
                i=findx(y);  //在x值查詢數組中,下標爲i的座標是第一個x=y的點
                for(;i<n;i++)
                {
                    if(arrx[i].x!=y)break;  //直到座標的x值不等於y或訪問到數組末尾,結束循環
                    else if(!flag[arrx[i].f])  //該點未訪問
                        flag[arrx[i].f]=true,sum++;  //標記爲訪問並且改變計數變量
                }
            }
            else  //同上
            {
                i=findy(y);
                for(;i<n;i++)
                {
                    if(arry[i].y!=y) break;
                    else if(!flag[arry[i].f])
                        flag[arry[i].f]=true,sum++;
                }
            }
            printf("%d\n",sum);
        }
        printf("\n");
    }
    return 0;
}


發佈了150 篇原創文章 · 獲贊 35 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章