1. 程式人生 > >BZOJ 1227: [SDOI2009]虔誠的墓主人 樹狀陣列 組合數

BZOJ 1227: [SDOI2009]虔誠的墓主人 樹狀陣列 組合數

1227: [SDOI2009]虔誠的墓主人

Time Limit: 5 Sec Memory Limit: 259 MB
Submit: 1324 Solved: 629

Description

小W 是一片新造公墓的管理人。公墓可以看成一塊N×M 的矩形,矩形的每個格點,要麼種著一棵常青樹,要麼是一塊還沒有歸屬的墓地。當地的居民都是非常虔誠的基督徒,他們願意提前為自己找一塊合適墓地。為了體現自己對主的真誠,他們希望自己的墓地擁有著較高的虔誠度。一塊墓地的虔誠度是指以這塊墓地為中心的十字架的數目。一個十字架可以看成中間是墓地,墓地的正上、正下、正左、正右都有恰好k 棵常青樹。小W 希望知道他所管理的這片公墓中所有墓地的虔誠度總和是多少

Input

第一行包含兩個用空格分隔的正整數N 和M,表示公墓的寬和長,因此這個矩形公墓共有(N+1) ×(M+1)個格點,左下角的座標為(0, 0),右上角的座標為(N, M)。第二行包含一個正整數W,表示公墓中常青樹的個數。第三行起共W 行,每行包含兩個用空格分隔的非負整數xi和yi,表示一棵常青樹的座標。輸入保證沒有兩棵常青樹擁有相同的座標。最後一行包含一個正整數k,意義如題目所示。

Output

包含一個非負整數,表示這片公墓中所有墓地的虔誠度總和。為了方便起見,答案對2,147,483,648 取模。

Sample Input

5 6

13

0 2

0 3

1 2

1 3

2 0

2 1

2 4

2 5

2 6

3 2

3 3

4 3

5 2

2

Sample Output

6

HINT

圖中,以墓地(2, 2)和(2, 3)為中心的十字架各有3個,即它們的虔誠度均為3。其他墓地的虔誠度為0。

所有資料滿足1 ≤ N, M ≤ 1,000,000,000,0 ≤ xi ≤ N,0 ≤ yi ≤ M,1 ≤ W ≤ 100,000, 1 ≤ k ≤ 10。存在50%的資料,滿足1 ≤ k ≤ 2。存在25%的資料,滿足1 ≤ W ≤ 10000。

注意:”恰好有k顆樹“,這裡的恰好不是有且只有,而是從>=k的樹中恰好選k棵

Source

水題一道,我也就做了五個小時罷了,明天來寫題解

第二天:今天考試AK啦,超開心!233
這道題的思路相當巧妙,我們要求所有墓的虔誠度之和,其實就是求每個墓,可以組合出多少十字架,然後計數算和
對於一座墓,我們對他的計算應該是上面的樹和k的組合數,下面的樹和k的組合數,左邊的樹和k的組合數,右邊的樹和k的組合數,這四個數的乘積
我們令l表示這棵樹的右邊的墓穴(到下一棵樹為止)的左邊有多少棵樹
令r表示這棵樹的左邊的墓穴(到下一棵樹為止)的右邊有多少棵樹
我們令u表示這棵樹的下面的墓穴(到下一棵樹為止)的上面有多少棵樹
又令d表示這棵樹的上面的墓穴(到下一棵樹為止)的下面有多少棵樹
而我們發現一個很神奇的事情,就是對於在同一行的樹,我們可以固定兩棵樹,而在這兩個點之間的所有墓(這兩個點之間沒有樹了,我們細分到最小單位),於是這些墓的左邊的樹和k的組合數和右邊的樹和k的組合數都是一樣的,所以我們計算這個區間的時候,左邊的樹和k的組合數和右邊的樹和k的組合數的乘積是作為常數來看待的,因此我們只需要知道這中間的所有點分別的上面的樹和k的組合數乘以下面的樹和k的組合數的和即可,那麼我們怎麼求呢?顯然用樹狀陣列就可以了,我們把一個點上面的樹和k的組合數乘以下面的樹和k的組合數作為這個點的資訊,每次我們修改這個資訊,修改的會在下一層用到,而這一層用到的都是上一層的,因此我們單點修改區間詢問即可,搞一個這個東西的字首和,每次修改,然後查詢一下,累計答案即可

最後注意一下離散化x座標,然後按照y座標排序,然後注意一下預處理組合數就可以了
這道題真的是思路非常巧妙,也融合了幾個知識點,對思維的訓練也非常強

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 100010;
struct LSH { int x, id; }lsh[MAXN];
struct Tree { int x, y, l, r, u, d; } a[MAXN];
int cnt, n, k, C[MAXN], X, Y, sum[MAXN], c[MAXN][15]; 
void modify( int x, int v ) { for( ; x <= cnt; x += x & -x ) C[x] += v; }
int query(int x){ int tmp=0; for(; x; x -= x & -x ) tmp += C[x]; return tmp; }
bool cmp1( const Tree &a, const Tree &b ) {
    if( a.y != b.y ) return a.y < b.y;
    else             return a.x < b.x;
}
bool cmp0( const LSH &a, const LSH &b ) { return a.x < b.x; }

int main( ) {
    scanf( "%d%d%d", &X, &Y, &n );
    for( register int i = 1; i <= n; i++ ) {
        scanf( "%d%d", &a[i].x, &a[i].y );
        lsh[i].x = a[i].x; lsh[i].id = i;
    }
    sort( lsh + 1, lsh + n + 1, cmp0 );cnt = 0;
    lsh[0].x = -2147483640;
    for( register int i = 1; i <= n; i++ ) {
        if( lsh[i].x != lsh[ i - 1 ].x ) cnt++;
        a[lsh[i].id].x = cnt;
    }
    sort( a + 1, a + n + 1, cmp1 ); //按照y為第一關鍵字排序 

    int tmp = 0, ans = 0;
    for( register int i = 1; i <= n; i++ ) {
        if( a[i].y == a[ i - 1 ].y ) tmp++;
        else                         tmp = 1;
        a[i].l = tmp; sum[a[i].x]++;
        a[i].d = sum[a[i].x];
    }
    tmp = 0;
    for( register int i = n; i; i-- ) {
        if( a[i].y == a[ i + 1 ].y ) tmp++;
        else                         tmp = 1;
        a[i].r = tmp; a[i].u = sum[a[i].x] - a[i].d;
    }/*
    for( register int i = 1; i <= n; i++ ) {
        printf( "%a[%d]::%d %d %d %d %d %d\n", i, a[i].x, a[i].y, a[i].l, a[i].r, a[i].u, a[i].d );
    }*/
    c[0][0] = 1; scanf( "%d", &k );
    for( register int i = 1; i <= n; i++ ) { c[i][0] = 1;
        for( register int j = 1; j <= k && j <= i; j++ ) c[i][j] = c[ i - 1 ][j] + c[ i - 1 ][ j - 1 ];
    }/*
    printf( "\n" );
    for( register int i = 1; i <= n; i++ ) {
        for( register int j = 1; j <= k; j++ ) {
            printf( "%d ", c[i][j] );
        }
        printf( "\n" );
    }*/
    for( register int i = 1; i <= n; i++ ) {
        modify( a[i].x, c[a[i].d][k] * c[a[i].u][k] - query( a[i].x ) + query( a[i].x - 1 ) );
        if( i > 1 && a[i].y == a[ i - 1 ].y ) ans += c[a[ i - 1 ].l][k] * c[a[i].r][k] * ( query( a[i].x - 1 ) - query( a[ i - 1 ].x ) );
    }
    printf( "%d\n", ans&2147483647 );
    return 0;
}

這裡寫圖片描述