agc018 E - Sightseeing Plan

题目叙述

给定三个矩形,保证严格从左下到右上排列,每个矩形內部选择一个点,求从左下走到右上经过中间那个点的方案数。

题解

直接做是直接六个 的。不好。
考虑组合意义,相当于从左下矩形内的一个点出发,走到右上,计算中间这个矩形内路径中的点数之和。看起来这个转化其实没什么用,但实际上大有用处。
不能转化成这样之后,再拆分贡献转化回去。考虑将路径上的点数表示成 Δx+Δy+1
这怎么算,如果写成这样可能不容易看出来。。。应该写成 (x1+y1)(x0+y0)+1
这样只需要枚举每个边界,计算经过这个边界的方案数量就可以了。
另外,别忘记 +1 ,这就是说统计经过这个矩形的路径数量。

总结

  • 计数题要试着把答案代数化。
  • 记得分类。合并一些答案。

代码

#include <cstdio>
#include <iostream>
#define y1 what_a_y1
#define macro_expand(x) #x
#define print_macro(x) printf("%s\n",macro_expand(x))
#define FOR(i,l,r) for(int i=(l),i##ADJK=(r);i<=i##ADJK;++i)
#define ROF(i,r,l) for(int i=(r),i##ADJK=(l);i>=i##ADJK;--i)
using namespace std;
typedef long long LL;
const int MN=1e6+6,RN=1e6,Mod=1e9+7;
int ad(int x,int y){return ((x+y)>=Mod)?(x+y-Mod):(x+y);}
int dc(int x,int y){return ((x-y)<0)?(x-y+Mod):(x-y);}
int ml(int x,int y){return (LL)x*y%Mod;}
int add(int &x,int y){return ((x+=y)>=Mod)?(x-=Mod):x;}
int dec(int &x,int y){return ((x-=y)<0)?(x+=Mod):x;}
int ksm(int x,int y){
	int ret=1;
	for(;y;y>>=1,x=ml(x,x))if(y&1)ret=ml(ret,x);
	return ret;
}
int x1,x2,x3,x4,x5,x6;
int y1,y2,y3,y4,y5,y6;
int fac[MN*2],caf[MN*2];
void init(){
	fac[0]=1;
	FOR(i,1,2*RN)fac[i]=ml(fac[i-1],i);
	caf[2*RN]=ksm(fac[2*RN],Mod-2);
	ROF(i,2*RN-1,0)caf[i]=ml(caf[i+1],i+1);
}
int binom(int u,int d){
	if(d<0||u<d)return 0;
	return ml(fac[u],ml(caf[d],caf[u-d]));
}
int cal1(int A,int B,int C,int D){
	return dc(ad(binom(B+D+2,D+1),binom(A+C,C)),ad(binom(A+D+1,D+1),binom(B+C+1,C)));
}
int cal2(int A,int B,int C,int D){
	return ml(cal1(A-x2,A-x1,B-y2,B-y1),cal1(x5-C,x6-C,y5-D,y6-D));
}
int ans;
int main(){
	freopen("e.in","r",stdin);
	freopen("e.out","w",stdout);
	init();
	scanf("%d%d%d%d%d%d",&x1,&x2,&x3,&x4,&x5,&x6);
	scanf("%d%d%d%d%d%d",&y1,&y2,&y3,&y4,&y5,&y6);
	int cnt=0;
	FOR(i,x3,x4){
		int tmp=0;
		add(cnt,tmp=cal2(i,y4,i,y4+1));
		add(ans,ml(i+y4,tmp));
	}
	FOR(i,y3,y4){
		int tmp=0;
		add(cnt,tmp=cal2(x4,i,x4+1,i));
		add(ans,ml(x4+i,tmp));
	}
	add(ans,cnt);
	FOR(i,y3,y4)dec(ans,ml(x3+i,cal2(x3-1,i,x3,i)));
	FOR(i,x3,x4)dec(ans,ml(i+y3,cal2(i,y3-1,i,y3)));
	printf("%d\n",ans);
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @   YouthRhythm  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示