1. 程式人生 > >bzoj-1227 虔誠的墓主人

bzoj-1227 虔誠的墓主人

題意:

在一個nxm的矩形裡給出一些w個點,這些是常青樹的座標;

求所有空地上下左右能組成的長度為k的十字架的總數;

1<=n,m<=10^9,1<=w<=100000,1<=k<=10

題解:

這道題思路很簡單,就是程式碼不太好寫;

首先如果是上下左右都沒有樹的點是必然沒有虔誠度的,所以我們可以肆無忌憚的離散化一下;

然後對於一塊墓地,它的答案就是C ( l , k ) *C ( r , k ) *C ( u , k ) *C ( d , k );

(這裡的l,r,u,d分別指某個點左右上下的常青樹個數)

顯然列舉每一塊墓地是超時的,那麼就考慮一次計算多個墓地;

對於在同一行兩棵樹之間的墓地來說,它們的 C ( l , k ) *C ( r , k )是相同的;

答案就是C ( l , k ) *C ( r , k ) * ∑C( u[i] , k )*C( d[i] , k );

求和的維護自然是樹狀陣列,那麼整道題的思路也就有了;

把所有樹按行來排序,然後遍歷維護出每棵樹的l,r,u,d;

維護樹狀陣列然後處理答案,時間複雜度是常數巨大的O(nlogn);

(程式碼寫的非常非常爛。。。3900+ms我都不太好意思貼。。。

更新:                                15/07/21

今天考試碰上原題。。。

怒切之後發現有點黑科技可以用;

mod的數恰好是1<<31所以讓int自然溢位就好;

最後輸出答案就是&(1<<31-1)就是答案;

這樣搞之後時間就是1864 ms啦;

程式碼:

15/07/21版:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110000
#define mod 2147483647
using namespace std;
struct node
{
	int x,y,tx,l,r,u,d;
	bool is;
}a[N];
int C[N][15];
int dis[N],tree[N],hash[N],last[N];
int cmp(node a,node b)
{
	if(a.y==b.y)
	return a.x<b.x;
	return a.y<b.y;
}
int lowbit(int x)
{
	return x&(-x);
}
void init()
{
	for(int i=0;i<N;i++)
	{
		C[i][0]=1;
		for(int j=1;j<=min(i,10);j++)
			C[i][j]=C[i-1][j]+C[i-1][j-1];
	}
}
void add(int x,int val)
{
	while(x<N)
	{
		tree[x]+=val;
		x+=lowbit(x);
	}
}
int query(int x)
{
	int ret=0;
	while(x)
	{
		ret+=tree[x];
		x-=lowbit(x);
	}
	return ret;
}
int main()
{
	freopen("cross.in","r",stdin);
	freopen("cross.out","w",stdout);
	int n,m,i,j,k,K,x,y,w,len,ans;
	init();
	scanf("%d%d%d",&n,&m,&w);
	for(i=1;i<=w;i++)
	{
		scanf("%d%d",&a[i].x,&a[i].y);
		dis[i]=a[i].x;
	}
	scanf("%d",&K);
	sort(dis+1,dis+w+1);
	len=unique(dis+1,dis+w+1)-dis-1;
	sort(a+1,a+w+1,cmp);
	for(i=1,y=-1,k=0;i<=w;i++)
	{
		if(a[i].y!=y)
			y=a[i].y,k=0;
		a[i].l=k;
		k++;
		a[i].tx=lower_bound(dis+1,dis+len+1,a[i].x)-dis;
		a[i].d=hash[a[i].tx];
		hash[a[i].tx]++;
		if(a[last[a[i].tx]].y+1==a[i].y)
			a[last[a[i].tx]].is=1;
		last[a[i].tx]=i;
	}
	for(i=w,y=-1,k=0;i>=1;i--)
	{
		if(a[i].y!=y)
			y=a[i].y,k=0;
		a[i].r=k;
		k++;
		a[i].u=hash[a[i].tx]-a[i].d-1;
	}
	for(i=1,y=-1,ans=0;i<=w;i++)
	{
		if(a[i].is!=1)
		add(a[i].tx,C[a[i].u][K]*C[a[i].d+1][K]-(query(a[i].tx)-query(a[i].tx-1)));
		if(a[i].y==a[i+1].y)
			ans+=C[a[i].l+1][K]*C[a[i+1].r+1][K]*(query(a[i+1].tx-1)-query(a[i].tx));
	}
	printf("%d",(ans)&mod);
	return 0;
}

舊版:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 110000
#define mod 2147483648ll
using namespace std;
typedef long long ll;
struct node
{
	ll dx,dy,x,y,l,r,u,d;
	bool is;
}a[N];
ll disx[N],disy[N];
ll tempx[N],tempy[N];
ll C[N][20],q[N];
ll tree[N];
int cmpll(ll a,ll b)
{
	return a<b;
}
int cmpnode(node a,node b)
{
	if(a.y==b.y)
	return a.x<b.x;
	return a.y<b.y;
}
ll mul(ll x,ll y)
{
	ll ret=0;
	while(y)
	{
		if(y&1)
		ret=(ret+x)%mod;
		x=(x+x)%mod;
		y>>=1;
	}
	return ret;
}
ll lowbit(ll k)
{
	return k&(-k);
}
void update(ll k,ll val)
{
	while(k<=100000)
	{
		tree[k]=(tree[k]+val)%mod;
		k+=lowbit(k);
	}
}
ll query(ll k)
{
	ll ret=0;
	while(k)
	{
		ret=(ret+tree[k])%mod;
		k-=lowbit(k);
	}
	return ret;
}
int main()
{
	ll n,m,w,i,j,k,x,y,cnt,lenx,leny,ans,st,en;
	scanf("%lld%lld%lld",&n,&m,&w);
	for(i=1;i<=w;i++)
	{
		scanf("%lld%lld",disx+i,disy+i);
		a[i].x=disx[i],a[i].y=disy[i];
	}
	scanf("%lld",&k);
	sort(disx+1,disx+1+w,cmpll);
	sort(disy+1,disy+1+w,cmpll);
	lenx=unique(disx+1,disx+1+w)-disx-1;
	leny=unique(disy+1,disy+1+w)-disy-1;
	sort(a+1,a+w+1,cmpnode);
	for(i=1,y=1,cnt=0;i<=w;i++)
	{
		a[i].dx=lower_bound(disx+1,disx+1+lenx,a[i].x)-disx;
		a[i].dy=lower_bound(disy+1,disy+1+leny,a[i].y)-disy;
		if(a[i].dy==y)
			a[i].l=cnt++;
		else
			tempy[y]=cnt,a[i].l=0,cnt=1,y=a[i].dy;
		a[i].d=tempx[a[i].dx];
		tempx[a[i].dx]++;
	}
	tempy[a[w].dy]=cnt;
	for(i=1;i<=w;i++)
	{
		a[i].u=tempx[a[i].dx]-a[i].d-1;
		a[i].r=tempy[a[i].dy]-a[i].l-1;
	}
	st=1,en=0;
	for(i=w,y=leny,x=w;i>0;i--)
	{
		if(a[i].dy!=y)
		{
			while(st<=en)	st++;
			for(j=x;j>i;j--)
				q[++en]=a[j].dx;
			x=i;
			y=a[i].dy;
		}
		while(q[st]>a[i].dx&&st<=en)	st++;
		if(q[st]==a[i].dx)	a[i].is=1;
	}
	for(i=0;i<=w;i++)
	{
		C[i][0]=1;
		for(j=1;j<=min(i,k);j++)
			C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
	}
	y=a[1].dy,x=1;
	for(i=1,ans=0;i<=w;i++)
	{
		if(a[i].l+1>=k&&a[i].r>=k&&a[i+1].dx-1>a[i].dx)
		{
			ans=(ans+(((query(a[i+1].dx-1)-query(a[i].dx))%mod+mod)%mod)*
					   (C[a[i].l+1][k]*C[a[i].r][k]%mod))%mod;
		}
		if(a[i].is)
		update(a[i].dx,((C[a[i].u-1][k]*C[a[i].d+1][k]%mod)-
					   ((query(a[i].dx)-query(a[i].dx-1))%mod+mod)%mod+mod)%mod);
 		else
		update(a[i].dx,((C[a[i].u][k]*C[a[i].d+1][k]%mod)-
					   ((query(a[i].dx)-query(a[i].dx-1))%mod+mod)%mod+mod)%mod);
	}
	printf("%lld",ans%mod);
	return 0;
}


相關推薦

BZOJ-1227 虔誠墓主人 樹狀陣列+離散化+組合數學

1227: [SDOI2009]虔誠的墓主人 Time Limit: 5 Sec Memory Limit: 259 MB Submit: 914 Solved: 431 [Submit][Status][Discuss] Description

bzoj-1227 虔誠墓主人

題意: 在一個nxm的矩形裡給出一些w個點,這些是常青樹的座標; 求所有空地上下左右能組成的長度為k的十字架的總數; 1<=n,m<=10^9,1<=w<=100000,1<=k<=10 題解: 這道題思路很簡單,就是程式碼不太好寫;

bzoj 1227: [SDOI2009]虔誠墓主人

pro stream 存在 i++ namespace include div ont ans Description 小W 是一片新造公墓的管理人。公墓可以看成一塊N×M 的矩形,矩形的每個格點,要麽種著一棵常青樹,要麽是一塊還沒有歸屬的墓地。當地的居民都是非常虔誠的基

BZOJ 1227 [SDOI2009]虔誠墓主人 - 掃描線

getchar one 離散化 push_back 合數 getchar() owb str += Solution 離散化 掃描線, 並用 $rest[i]$ 和 $cnt[i]$ 記錄 第$i$列 總共有 $cnt[i]$棵常青樹, 還有$rest[i]$ 沒有被掃描

BZOJ 1227: [SDOI2009]虔誠墓主人 數狀陣列

Description 小W 是一片新造公墓的管理人。公墓可以看成一塊N×M 的矩形,矩形的每個格點,要麼種著一棵常青樹,要麼是一塊還沒有歸屬的墓地。當地的居民都是非常虔誠的基督徒,他們願意提前為自己找一塊合適墓地。為了體現自己對主的真誠,他們希望自己的墓地擁

[bzoj]1227: [SDOI2009]虔誠墓主人【樹狀陣列】

** Description ** 小W 是一片新造公墓的管理人。公墓可以看成一塊N×M 的矩形,矩形的每個格點,要麼種著一棵常青樹,要麼是一塊還沒有歸屬的墓地。當地的居民都是非常虔誠的基督徒,他們願意提前為自己找一塊合適墓地。為了體現自己對主的真誠,他們

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

1227: [SDOI2009]虔誠的墓主人 Time Limit: 5 Sec Memory Limit: 259 MB Submit: 1324 Solved: 629 Description 小W 是一片新造公墓的管理人。公墓可以看成一塊N

bzoj 1227虔誠墓主人(樹狀陣列)

傳送門biu~ 上下左右沒有樹的墓地必然沒有虔誠度,所以將原圖離散化成一個最大為w×ww×w的圖。 對於每塊墓地,令在它上、下、左、右方向常青樹的數目分別為uu,pp,ll,rr。則以這個點為中心的

BZOJ1227: [SDOI2009]虔誠墓主人

包含 lan mst tput lib main 數組 script 部分 1227: [SDOI2009]虔誠的墓主人 Time Limit: 5 Sec Memory Limit: 259 MBSubmit: 1306 Solved: 615[Submit][

BZOJ1227 [SDOI2009]虔誠墓主人 【樹狀數組】

lag AI namespace flag pos 上下左右 OS 離散化 str 題目 小W 是一片新造公墓的管理人。公墓可以看成一塊N×M 的矩形,矩形的每個格點,要麽種著一棵常青樹,要麽是一塊還沒有歸屬的墓地。當地的居民都是非常虔誠的基督徒,他們願意提前為自己找一塊合

Luogu 2154 [SDOI2009]虔誠墓主人

分享 esp 我們 open index 一個空格 nod 狀態 nom 弄了很久,狀態很爛…… 首先發現可用的點一共只有$1e5$個,所以可以離散化坐標來方便計算。 發現對於一個空格,設它的上、下、左、右分別有$u, d, l, r$個點,

【BZOJ1227】[SDOI2009]虔誠墓主人(線段樹)

方案 mod printf math std code tchar bre getchar 【BZOJ1227】[SDOI2009]虔誠的墓主人(線段樹) 題面 BZOJ 洛谷 題解 顯然發現答案就是對於每一個空位置,考慮上下左右各有多少棵樹,然後就是這四個方向上樹的數量中

[luogu2154 SDOI2009] 虔誠墓主人(樹狀數組+組合數)

得到 sdoi2009 define lin 思路 fin size set new 傳送門 Solution 顯然每個點的權值可以由當前點上下左右的樹的數量用組合數\(O(1)\)求出,但這樣枚舉會T 那麽我們考慮一段連續區間,對於一行中兩個常青樹中間的部分左右樹的數量一

2018.10.25 bzo1227: [SDOI2009]虔誠墓主人(組合數學+掃描線+bit)

傳送門 有點難調啊。其實是我自己sb了 不過交上去1A1A1A還是平衡了一下心態。 所以這道題怎麼做呢? 我們考慮對於一個點(x,y)(x,y)(x,y)如果這個點成為中心,正左/右/上/下分別有l/r

BZOJ1227 SDOI2009 虔誠墓主人【樹狀陣列+組合數】【好題】*

BZOJ1227 SDOI2009 虔誠的墓主人 Description 小W 是一片新造公墓的管理人。公墓可以看成一塊N×M 的矩形,矩形的每個格點,要麼種著一棵常青樹,要麼是一塊還沒有歸屬的墓地。當地的居民都是非常虔誠的基督徒,他們願意提前為自己找一塊合

【SDOI2009】【BZOJ1227】虔誠墓主人

Description 小W 是一片新造公墓的管理人。公墓可以看成一塊N×M 的矩形,矩形的每個格點,要麼種著一棵常青樹,要麼是一塊還沒有歸屬的墓地。當地的居民都是非常虔誠的基督徒,他們願意提前為自己找一塊合適墓地。為了體現自己對主的真誠,他們希望自己的墓地擁

[BZOJ1227][SDOI2009]虔誠墓主人(樹狀陣列+掃描線)

題目: 我是超連結 題解: 首先離散橫縱座標. 以縱座標為第一關鍵字,橫座標為第二關鍵字排序依次考慮每個點. 對於相鄰的兩個點a,b; 如果a.y=b.y;設在這一行,a左邊算上a有sa棵樹,b右邊算上b有sb棵樹. 那麼這一行上a,b之間的點都會

【SDOI2009】bzoj1227 虔誠墓主人

Description 小W 是一片新造公墓的管理人。公墓可以看成一塊N×M 的矩形,矩形的每個格點,要麼種著一棵常青樹,要麼是一塊還沒有歸屬的墓地。當地的居民都是非常虔誠的基督徒

bzoj1227 [SDOI2009]虔誠墓主人(組合公式+離散化+線段樹)

1227: [SDOI2009]虔誠的墓主人 Time Limit: 5 Sec  Memory Limit: 259 MB Description 小W 是一片新造公墓的管理人。公墓可以看成一塊N×M 的矩形,矩形的每個格點,要麼種著一棵常青樹,要麼是一塊還沒有歸屬的墓地

虔誠墓主人(BZOJ1227)(洛谷P2154)解題報告

emp 裝飾 楊輝三角 span 記錄 upd 藍色 標簽 for 題目描述 小W是一片新造公墓的管理人。公墓可以看成一塊N×M的矩形,矩形的每個格點,要麽種著一棵常青樹,要麽是一塊還沒有歸屬的墓地。 當地的居民都是非常虔誠的基督徒,他們願意提前為自己找一塊