zoukankan      html  css  js  c++  java
  • luoguP2154 [SDOI2009]虔诚的墓主人

    SDOI2009虔诚的墓主人

    喜闻乐见,我终于把此题读懂了。。所以可以写了。

    其实就是让我们求有多少个十字架 一个十字架的定义为中间有一个空地 周围4个正方向都有k棵树。

    不难想到nm的暴力 我们预处理一下当前行有多少棵树 当前列有多少棵树 用组合数算一下即可。

    如何优化 我们发现在暴力的过程中很多点的代价是相同的 可以考虑将这些点压到一起来计算。

    我们发现对于所有的行来说 两颗树之间的空隙 答案可能相同。

    不妨枚举所有的行的空隙 考虑如何求出答案 我们对列求方案数的和乘起来即可。

    列怎么维护方案数?可以采用线段树或者树状数组来搞 注意离散化。。

    这里取模对2^31次方取模 挺有意思的 这个是在提醒我们直接int即可 不能开unsigned int 这个是对2^32次方取模 如果爆int了那么符号为翻转 所以直接int即可。

    但是组合数就不能再预处理阶乘了 可能存在某些数字是没有逆元的 好像不互质都没逆元来着。

    递推组合数即可。由于还要搞行的方案数建议也离散一下 不然需要开map...

    题解中写的一堆看不懂东西 我也没管 方法好像是一样的。

    const int MAXN=100010<<1;
    int n,m,w,k,ans,top;
    struct wy
    {
    	int x,y;
    	inline int friend operator <(wy a,wy b){return a.y==b.y?a.x<b.x:a.y<b.y;}
    }t[MAXN];
    int b[MAXN];
    int c[MAXN][11];
    int pos[MAXN],pos1[MAXN];
    int s[MAXN],sum[MAXN],sum1[MAXN];
    inline void prepare()
    {
    	c[0][0]=1;
    	for(int i=1;i<=w;++i)
    	{
    		c[i][0]=1;
    		for(int j=1;j<=min(i,k);++j)
    			c[i][j]=c[i-1][j]+c[i-1][j-1];
    	}
    }
    inline void discrete()
    {
    	sort(b+1,b+1+w*2);
    	rep(1,w+w,i)if(i==1||b[i]!=b[i-1])b[++top]=b[i];
    	rep(1,w,i)
    	{
    		y(i)=lower_bound(b+1,b+1+top,y(i))-b;
    		x(i)=lower_bound(b+1,b+1+top,x(i))-b;
    	}
    }
    inline void add(int x,int y){while(x<=top){s[x]+=y;x+=x&(-x);}}
    inline int ask(int x){int cnt=0;while(x){cnt+=s[x];x-=x&(-x);};return cnt;}
    int main()
    {
    	freopen("1.in","r",stdin);
    	get(n);get(m);get(w);
    	rep(1,w,i)get(x(i)),b[i]=get(y(i)),b[i+w]=x(i);
    	get(k);discrete();prepare();
    	rep(1,w,i)++pos1[y(i)],++sum[x(i)];
    	sort(t+1,t+1+w);
    	int last=-1,p=0;
    	rep(1,w,i)
    	{
    		if(y(i)==last)
    		{
    			if(x(i)!=p+1)
    			{
    				int w=ask(x(i)-1)-ask(p);
    				int w1=c[pos1[y(i)]-pos[y(i)]][k]*c[pos[y(i)]][k];
    				ans+=w*w1;
    			}
    		}
    		last=y(i),p=x(i);
    		++pos[y(i)];
    		add(x(i),-c[sum[x(i)]][k]*c[sum1[x(i)]][k]);
    		--sum[x(i)];++sum1[x(i)];
    		add(x(i),c[sum[x(i)]][k]*c[sum1[x(i)]][k]);
    	}
    	printf("%d
    ",(ans+mod)%mod);
    	return 0;
    }
    

    值得一提的是 我写的时候没考虑清楚 行列没分清 所以代码中写的是逐列的 和上文刚好相反。。

  • 相关阅读:
    NOIP201* 游记
    [Luogu3378] 【模板】堆 题解
    [BZOJ5105]【[Code+#1]晨跑】 题解
    牛客多校第九场 E All men are brothers 并查集/组合论
    牛客多校第九场 D Knapsack Cryptosystem 背包
    牛客多校第九场 B Quadratic equation 模平方根
    hdu多校第八场 1011 (hdu6667) Roundgod and Milk Tea 二分图匹配
    hdu多校第八场 1010(hdu6666) Quailty and CCPC 排序/签到
    hdu多校第八场 1003 (hdu6659) Acesrc and Good Numbers 数论/打表
    hdu多校第八场 1009 (hdu6665) Calabash and Landlord 计算几何/dfs
  • 原文地址:https://www.cnblogs.com/chdy/p/12482378.html
Copyright © 2011-2022 走看看