題目 小W 是一片新造公墓的管理人。公墓可以看成一塊N×M 的矩形,矩形的每個(gè)格點(diǎn),要么種著一棵常青樹,要么是一塊還沒有歸屬的墓地。當(dāng)?shù)氐木用穸际欠浅r\的基督徒,他們愿意提前為自己找一塊合適墓地。為了體現(xiàn)自己對主的真誠,他們希望自己的墓地?fù)碛兄^高的虔誠度。一塊墓地的虔誠度是指以這塊墓地為中心的十字架的數(shù)目。一個(gè)十字架可以看成中間是墓地,墓地的正上、正下、正左、正右都有恰好k 棵常青樹。小W 希望知道他所管理的這片公墓中所有墓地的虔誠度總和是多少
輸入格式 第一行包含兩個(gè)用空格分隔的正整數(shù)N 和M,表示公墓的寬和長,因此這個(gè)矩形公墓共有(N+1) ×(M+1)個(gè)格點(diǎn),左下角的坐標(biāo)為(0, 0),右上角的坐標(biāo)為(N, M)。第二行包含一個(gè)正整數(shù)W,表示公墓中常青樹的個(gè)數(shù)。第三行起共W 行,每行包含兩個(gè)用空格分隔的非負(fù)整數(shù)xi和yi,表示一棵常青樹的坐標(biāo)。輸入保證沒有兩棵常青樹擁有相同的坐標(biāo)。最后一行包含一個(gè)正整數(shù)k,意義如題目所示。
輸出格式 包含一個(gè)非負(fù)整數(shù),表示這片公墓中所有墓地的虔誠度總和。為了方便起見,答案對2,147,483,648 取模。
輸入樣例 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
輸出樣例 6
提示 圖中,以墓地(2, 2)和(2, 3)為中心的十字架各有3個(gè),即它們的虔誠度均為3。其他墓地的虔誠度為0。
所有數(shù)據(jù)滿足1 ≤ N, M ≤ 1,000,000,000,0 ≤ xi ≤ N,0 ≤ yi ≤ M,1 ≤ W ≤ 100,000, 1 ≤ k ≤ 10。存在50%的數(shù)據(jù),滿足1 ≤ k ≤ 2。存在25%的數(shù)據(jù),滿足1 ≤ W ≤ 10000。
注意:”恰好有k顆樹“,這里的恰好不是有且只有,而是從>=k的樹中恰好選k棵
題解 題目中的模數(shù)等于\(2^31\) ,所以int自然溢出就相當(dāng)于取模 我們記一個(gè)點(diǎn)上下左右的樹數(shù)量為u、d、l、r,則每個(gè)點(diǎn)的貢獻(xiàn)是\(C_{u}^{k} * C_ozvdkddzhkzd^{k} * C_{l}^{k} * C_{r}^{k}\) 點(diǎn)的范圍很大,我們將其離散化到100000以內(nèi) 但總共\(W^2\) 個(gè)點(diǎn),不能直接算,但樹只有\(W\) 個(gè),考慮從樹出發(fā) 我們將所有樹排序后,對于橫坐標(biāo)相同的兩棵樹之間的點(diǎn),其式子中的\(C_{u}^{k} * C_ozvdkddzhkzd^{k}\) 是一樣的 我們用樹狀數(shù)組維護(hù)\(C_{l}^{k} * C_{r}^{k}\) ,就可以加速運(yùn)算了
#include<iostream>
#include<cstdio>
#include<algorithm>
#define lbt(x) (x & -x)
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 1000000000;
inline int read(){int out = 0,flag = 1; char c = getchar();while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}return out * flag;
}
int s[maxn],C[maxn][11],b[maxn],tot,n,k;
int U[maxn],D[maxn],L[maxn],R[maxn],V[maxn];
struct point{int x,y;}p[maxn];
int getn(int x){return lower_bound(b + 1,b + 1 + tot,x) - b;}
inline bool operator <(const point& a,const point& b){return a.x == b.x ? a.y < b.y : a.x < b.x;
}
void add(int u,int v){while (u <= tot) s[u] += v,u += lbt(u);}
void mus(int u,int v){while (u <= tot) s[u] -= v,u += lbt(u);}
int query(int u){int ans = 0; while (u) ans += s[u],u -= lbt(u); return ans;}
int sum(int l,int r){return query(r) - query(l - 1);}
void cal(){for (int i = 0; i <= n; i++){C[i][0] = C[i][i] = 1;for (int j = 1; j <= i && j <= 10; j++)C[i][j] = C[i - 1][j] + C[i - 1][j - 1];}
}
void init(){read(); read();n = read();cal();for (int i = 1; i <= n; i++)b[i] = p[i].x = read(),p[i].y = read();sort(b + 1,b + 1 + n); tot = 1;for (int i = 2; i <= n; i++) if (b[i] != b[tot]) b[++tot] = b[i];for (int i = 1; i <= n; i++) p[i].x = getn(p[i].x);for (int i = 1; i <= n; i++) b[i] = p[i].y;sort(b + 1,b + 1 + n); tot = 1;for (int i = 2; i <= n; i++) if (b[i] != b[tot]) b[++tot] = b[i];for (int i = 1; i <= n; i++) p[i].y = getn(p[i].y);k = read();
}
void solve(){sort(p + 1,p + 1 + n);int ans = 0;for (int i = 1; i <= n; i++) U[p[i].x]++,R[p[i].y]++;for (int i = 1; i <= n; i++){if (i > 1 && p[i - 1].x == p[i].x && p[i - 1].y + 1 < p[i].y)ans += C[U[p[i].x]][k] * C[D[p[i].x]][k] * sum(p[i - 1].y + 1,p[i].y - 1);U[p[i].x]--; D[p[i].x]++;R[p[i].y]--; L[p[i].y]++;add(p[i].y,-V[p[i].y]);add(p[i].y,V[p[i].y] = C[L[p[i].y]][k] * C[R[p[i].y]][k]);}cout << (ans >= 0 ? ans : ans + 2147483647 + 1) << endl;
}
int main(){init();solve();return 0;
}
轉(zhuǎn)載于:https://www.cnblogs.com/Mychael/p/8478222.html
總結(jié)
以上是生活随笔 為你收集整理的BZOJ1227 [SDOI2009]虔诚的墓主人 【树状数组】 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。