[BZOJ] 1293 - [SCOI2009] - 生日禮物 - 離散化 - 尺取法 - 狀態壓縮

1293: [SCOI2009]生日禮物

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2800  Solved: 1523
[Submit][Status][Discuss]

Description

小西有一條很長的綵帶,綵帶上掛着各式各樣的彩珠。已知彩珠有N個,分爲K種。簡單的說,可以將綵帶考慮爲x軸,每一個彩珠有一個對應的座標(即位置)。某些座標上可以沒有彩珠,但多個彩珠也可以出現在同一個位置上。 小布生日快到了,於是小西打算剪一段綵帶送給小布。爲了讓禮物綵帶足夠漂亮,小西希望這一段綵帶中能包含所有種類的彩珠。同時,爲了方便,小西希望這段綵帶儘可能短,你能幫助小西計算這個最短的長度麼?綵帶的長度即爲綵帶開始位置到結束位置的位置差。

Input

第一行包含兩個整數N, K,分別表示彩珠的總數以及種類數。接下來K行,每行第一個數爲Ti,表示第i種彩珠的數目。接下來按升序給出Ti個非負整數,爲這Ti個彩珠分別出現的位置。

Output

應包含一行,爲最短綵帶長度。

Sample Input

6 3
1 5
2 1 7
3 1 3 8

Sample Output

3

HINT

有多種方案可選,其中比較短的是1~5和5~8。後者長度爲3最短。
【數據規模】
對於50%的數據, N≤10000;
對於80%的數據, N≤800000;
對於100%的數據,1≤N≤1000000,1≤K≤60,0≤彩珠位置<2^31。

Source

做BZOJ是真的爽啊。。。

對拍造數據能力得到了顯著提升

先把所有位置離散化
狀壓每個位置上的綵球的狀況以及當前區間的綵球的情況
然後尺取法
當滿足條件的時候移動左區間

不滿足移動右區間

就搞出來了

狀壓要用 LL 存結果我用 int 存了卡死我

突然發現好像不要狀壓也能過= =!
不敢嘗試

反正我 A 了。。。。
#include <bits/stdc++.h>
#define pb push_back
#define LL long long
using namespace std;

const int N = 1000010;

vector<int> id;
int ma[N];
int mb[N];
LL cnt[N];
int mc[N];

int getid(int x)
{
    return lower_bound(id.begin(), id.end(), x) - id.begin();
}

int main()
{
    int n, m;
    int len;
    int l, r;
    LL li;///!!!!
    LL now;///!!!
    int ans;
    int be;

    while(scanf("%d%d", &n, &m) == 2){
        ans = 0x3f3f3f3f;
        be = 0;
        memset(cnt, 0, sizeof(cnt));
        memset(mc, 0, sizeof(mc));
        for(int i = 0; i < m; i ++){
            scanf("%d", &mb[i]);
            for(int j = 0; j < mb[i]; j ++){
                scanf("%d", &ma[be + j]);
                id.pb(ma[be + j]);
            }
            be += mb[i];
        }
        sort(id.begin(), id.end());
        id.erase(unique(id.begin(), id.end()), id.end());
        len = id.size();
        be = 0;
        for(int i = 0; i < m; i ++){
            for(int j = 0; j < mb[i]; j ++){
                cnt[getid(ma[be + j])] += (1ll * 1 << i);
            }
            be += mb[i];
        }
        li = (1ll * 1 << m) - 1;
        now = 0;
        l = 0;
        r = -1;
        while(l < len){
            if(r == len && now != li){
                break;
            }
            if(now == li){
                LL t = cnt[l];
                int num = 0;

                ans = min(ans, id[r] - id[l]);
                while(t){
                    if(t & 1){
                        mc[num] --;
                        if(!mc[num]){
                            now -= (1ll * 1 << num);
                        }
                    }
                    t >>= 1;
                    num ++;
                }
                l ++;
            }
            else{
                LL t;
                int num;

                r ++;
                t = cnt[r];
                num = 0;
                while(t){
                    if(t & 1){
                        mc[num] ++;
                        if(mc[num] == 1){
                            now += (1ll * 1 << num);
                        }
                    }
                    t >>= 1;
                    num ++;
                }
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章