bzoj2727: [HNOI2012]双十字

原创 2016年01月03日 11:59:43

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2727

思路:

先预处理出c[i],down[i]

c[i]表示i点向两侧最多扩展多远(不包括自身,因为长度为1的横线显然是不合题意的)

down[i]表示向下扩展多远(也不包括自身,因为"下端必须严格低于两条水平线段")

这个可以通过O(R*C)的预处理求得


首先我们枚举竖线,因为竖线只有一根

然后考虑对竖线一个点i,它做下十字的中心时的方案数

枚举i上面的点j做上十字的中心

求出当前的top,表示最高能到的点的行号

分情况讨论

1.c[j]>c[i] 枚举下十字的长度len,因为c[j]>c[i],所以上十字一定有len-1种长度可取,上横线以上的竖线长度有(j-top)种,下横线一下的竖线长度有down[i]种

ans=Σ(len=1...c[i]-1)*(j-top)*down[i]

=c[i]*(c[i]-1)/2*(j-top)*down[i]


2.c[j]<=c[i],这时上十字的长度不够了,我们可以拿总方案-不合法的方案

总方案:c[i]*c[j]*(j-top)*(down[i])

不合法的方案:c[j]*(c[j]+1)/2*(j-top)*(down[i])

因为所有上十字长度大于等于下十字长度的都不合法,这时c[j]<=c[i],所以类似情况1,等差数列求和即可

ans=(c[i]*c[j]-c[j]*(c[j]+1)/2)*(j-top)*(down[i])


这时暴力得答案就有80分

但这还不够,显然这是可以用树状数组优化的

开3个树状数组,把式子中关于j的三个部分维护起来,下标就是c[i]

t1维护(-c[j]*(c[j]+1)/2)*(j-top)

t2维护c[j]*(j-top)

t3维护(j-top)


每次在树状数组里相应区间查即可。


坑:"(事实上R*C可能稍大于原设定)"

“两条水平的线段不能在相邻的两行”也就是树状数组不能做完i就插入i,而是插入i-1


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef long long ll;
const int maxn=1300010,mod=1000000009,maxm=10010;
using namespace std;
int n,m,c[maxn],down[maxn],cnt;bool is[maxn];
int p(int x,int y){return (x-1)*m+y;}
struct Tbit{
	int ord[maxm],tot;ll v[maxn];
	void clear(){
		for (int i=1;i<=tot;i++)
			for (int j=ord[i];j<=m;j+=(j&(-j))) v[j]=0;
		tot=0;
	}
	void add(int x,ll val){
		ord[++tot]=x;
		for (;x<=m;x+=(x&(-x))) v[x]=(v[x]+val)%mod;
	}
	ll query(int x){
		ll res=0;
		for (;x;x-=(x&(-x))) res=(res+v[x])%mod;
		return res%mod;
	}
}t1,t2,t3;

void init(){
	scanf("%d%d%d",&n,&m,&cnt);
	for (int i=1,x,y;i<=cnt;i++) scanf("%d%d",&x,&y),is[p(x,y)]=1;
	
	for (int i=1;i<=n;i++){
		int now=0;
		for (int j=1;j<=m;j++){
			int t=p(i,j);
			if (is[t]) now=j;
			else c[t]=j-now-1;
		}
		now=m+1;
		for (int j=m;j;j--){
			int t=p(i,j);
			if (is[t]) now=j;
			else c[t]=min(c[t],now-j-1);
		}
	}
	for (int i=n;i;i--){
		for (int j=1;j<=m;j++){
			int t=p(i,j);
			if (is[t]) down[t]=-1;
			else if (i==n) down[t]=0;
			else down[t]=down[p(i+1,j)]+1;
		}
	}
}

//i在下,j在上
//c[j]<=c[i] ans=(c[i]*c[j]-c[j]*(c[j]+1)/2)*(j-top)*down[i]
//c[j]>c[i] ans=(c[i]-1)*c[i]/2*(j-top)*down[i]
//t1 -c[j]*(c[j]+1)/2*(j-top)
//t2 c[j]*(j-top)
//t3 (top-j)
void work(){
	ll ans=0;
	for (int j=1;j<=m;j++){
		t1.clear(),t2.clear(),t3.clear();
		int top=0;
		for (int i=1;i<=n;i++){
			int t=p(i,j);
			if (is[t]){top=i;t1.clear(),t2.clear(),t3.clear();continue;}
			ans+=t1.query(c[t])*down[t]%mod;
			ans+=t2.query(c[t])*c[t]*down[t]%mod;
			ans+=(t3.query(m)-t3.query(c[t]))*(c[t]-1)*c[t]/2*down[t]%mod;
			ans%=mod,t=p(i-1,j);
			if (i==1) continue;
			if (c[t]){
				t1.add(c[t],-1ll*c[t]*(c[t]+1)/2*(i-1-top-1));
				t2.add(c[t],c[t]*(i-1-top-1));
				t3.add(c[t],i-1-top-1);
			}
		}
	}
	printf("%lld\n",ans);
}

int main(){
	init(),work();
	return 0;
}




版权声明:本文为博主原创文章,未经博主允许不得转载。

hnoi2012 (bzoj2727~2734)

题目就不贴了,自己看吧。 这套题每道题如果会做的话写代码的过程真是轻松加愉快……湖南人出的题似乎都是这样……真有水平…… hnoi2012 day1: bzoj2727 ...

BZOJ 2727: [HNOI2012]双十字

如果你有一道题一上午都没调出来 那么一定是你取模取错了QAQ 下意识地对(1e9)+7取了模,现在才发现是(1e9)+9 这个首先推一下公式,然后开三个树状数组维护一下就好了 #include...
  • nlj1999
  • nlj1999
  • 2016年04月07日 11:43
  • 239

[BZOJ 2727][HNOI 2012]双十字(树状数组+计数问题)

题目链接http://www.lydsy.com/JudgeOnline/problem.php?id=2727思路这个题好难啊啊啊啊啊啊啊啊啊啊啊啊啊,花了我半天的时间去研究vfk和ydc的题解才算...
  • qpswwww
  • qpswwww
  • 2015年02月27日 19:56
  • 646

BZOJ 2730 [HNOI2012]矿场搭建 点双联通分量(割点)

题意: 链接. 方法: 点双联通分量(割点). 解析:  首先这道题有两个问,并且是无向图 第一问是任意删掉一个点后,满足剩下所有的点均可以找到一个出口,则最少安放的出口数是多少? 第二问是满足...
  • wzq_QwQ
  • wzq_QwQ
  • 2015年03月19日 15:12
  • 818

【BZOJ2729】【HNOI2012】排队 组合数 数论 Python高精度

题解: 代码里面有注释。 注意: Python2中的中文字符即使注释了,也会CE(当然,因为Python是直接运行,不编译,所以显示WA) 呃,而本地的Python3就不管它了。。 所以我的代码需...
  • Vmurder
  • Vmurder
  • 2015年01月21日 09:58
  • 1687

(bzoj 2734 [HNOI2012]集合选数)<状压DP>

转化为状压DP求解

[BZOJ 2731][HNOI 2012]三角形覆盖问题(计算几何+扫描线暴力)

题目链接http://www.lydsy.com/JudgeOnline/problem.php?id=2731思路裸的三角形求面积并问题,计算几何问题中这类求面积并的问题的通法就是对事件点做扫描线,...
  • qpswwww
  • qpswwww
  • 2015年03月10日 19:22
  • 1027

[BZOJ2730][HNOI2012]矿厂搭建--tarjan

点双连通分量模板–矿厂搭建 BZOJ2730 HNOI2012

BZOJ 2730 HNOI2012 矿场搭建 Tarjan

题目大意:给定一个无向图,要求将一些点设为出口 要求图中删掉任意一个点后剩余的任意一个点都与至少一个出口相连 求最少建多少个出口以及建最少出口的方案数 首先看到割点就是Tarjan搞 但是怎么搞 首先...
  • PoPoQQQ
  • PoPoQQQ
  • 2014年11月04日 14:29
  • 2209

BZOJ 2732 [HNOI2012]射箭

半平面交
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:bzoj2727: [HNOI2012]双十字
举报原因:
原因补充:

(最多只允许输入30个字)