JZOJ5457. 【NOIP2017提高A組衝刺11.6】項鍊

題意:

nodgd的粉絲太多了,每天都會有很多人排隊要簽名。
今天有n個人排隊,每個人的身高都是一個整數,且互不相同。很不巧,nodgd今天去忙別的事情去了,就只好讓這些粉絲們明天再來。同時nodgd提出了一個要求,每個人都要記住自己前面與多少個比自己高的人,以便於明天恢復到今天的順序。
但是,粉絲們或多或少都是有些失望的,失望使她們暈頭轉向、神魂顛倒,已經分不清楚哪一邊是“前面”了,於是她們可能是記住了前面比自己高的人的個數,也可能是記住了後面比自己高的人的個數,而且他們不知道自己記住的是哪一個方向。
nodgd覺得,即使這樣明天也能恢復出一個排隊順序,使得任意一個人的兩個方向中至少有一個方向上的比他高的人數和他記住的數字相同。可惜n比較大,顯然需要寫個程序來解決,nodgd很忙,寫程序這種事情就交給你了。

這題是個水題,比賽的時候想複雜了導致我怒剛2個小時沒剛出來。。
設suf,pre表示每個點前綴後綴有多少個比他大,用兩個bit維護,問題就在於我不是插入,而是每次交換,計算每次交換對於i,j之間的數的影響,然後除此之外還要看看是否能交換,因爲有兩個位置可交換,如果兩個位置都不能交換那麼肯定impossible,然後二分查找位置,判斷用bit處理,所以時間複雜度nlog^2.

以上是我的比賽想法,太過複雜,而且實現細節很多,再加上比賽機子c++直接爆炸,只能輸出調試,用拍還不能調用文件,導致我根本調不出來,直接GG。

事實上我也應該注意到這種做法實在是太過複雜,尤其是每次交換的時候不能保證交換完以後已經被交換過的肯定不會被再次交換。反思就是每次想題的時候正解想到是沒什麼問題的,問題在於我經常把代碼複雜化,很多能簡化的地方要多思考一下,不要着急上手。

好了現在講正解。事實上根本沒必要死死在原序列交換來交換去,完全可以新開一個答案數組往裏面插入,相信想到插入以後這題就很水了,每個數字插入的位置只有兩種可能,從小到大插入,如果b[i]>n-i明顯不合法,然後用線段樹維護區間空位數即可。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+5;
//map<int,int>pos[N];
int n,m;
struct node
{
    int x,y;
}a[N];
struct tree
{
    int l,r,size;
}t[N*4+10];
int val[N];
bool cmp(node a,node b)
{
    return a.x<b.x;
}
inline void build(int x,int l,int r)
{
    t[x].l=l,t[x].r=r;
    t[x].size=r-l+1;
    if (l==r)return;
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);  
} 
inline void ins(int x,int k,int v)
{
    t[x].size--;
    if (t[x].l==t[x].r)
    {
        val[t[x].l]=v;
        return;
    }
    if (t[x<<1].size>=k)ins(x<<1,k,v);
    else ins(x<<1|1,k-t[x<<1].size,v);
}
int main()
{
    freopen("queue.in","r",stdin);
    freopen("queue.out","w",stdout);
    scanf("%d",&n);
    fo(i,1,n)
    {
        scanf("%d%d",&a[i].x,&a[i].y);
    }
    sort(a+1,a+1+n,cmp);
    build(1,1,n);
    fo(i,1,n)
    {
        if (a[i].y>n-i)
        {
            printf("impossible\n");
            return 0;
        }
        int pos=a[i].y+1;
        pos=min(pos,n-a[i].y-i+1);
        ins(1,pos,a[i].x);
    }
    fo(i,1,n)printf("%d ",val[i]);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章