[HDU6482]A Path Plan

280 篇文章 1 订阅

题目

传送门 to HDU

思路

《尝试集》

显然是要减去所有相交的路径。

考虑枚举最后一个相交的点,那么其前面可以乱走,后面必须不相交。

f ( y , x , Δ x ) f(y,x,\Delta x) f(y,x,Δx) 表示,从 ( 0 , y ) (0,y) (0,y) 走到 ( x , 0 ) (x,0) (x,0) ( x + Δ x , 0 ) (x+\Delta x,0) (x+Δx,0) 的不相交——除了在起点 ( 0 , y ) (0,y) (0,y) 上相交——的路线数量。则

C x + y x C x + Δ x + y x + Δ x − ∑ 0 ≤ x 0 ≤ x ∑ 0 ≤ y 0 ≤ y ( C x 0 + y − y 0 x 0 ) 2 f ( y 0 , x − x 0 , Δ x ) = 0 C_{x+y}^{x}C_{x+\Delta x+y}^{x+\Delta x}-\sum_{0\le x_0\le x}\sum_{0\le y_0\le y}\left(C_{x_0+y-y_0}^{x_0}\right)^2 f(y_0,x-x_0,\Delta x)=0 Cx+yxCx+Δx+yx+Δx0x0x0y0y(Cx0+yy0x0)2f(y0,xx0,Δx)=0

这个式子的意义是枚举最后一个相交的点。把 Δ x \Delta x Δx 换成 x 2 − x 1 x_2-x_1 x2x1 ,把 x x x 换成 x 1 x_1 x1 ,把 x 0 x_0 x0 换成 x x x ,把 y 0 y_0 y0 换成 y y y ,把 y y y 换成 y 1 y_1 y1 ,我们有

∑ 0 ≤ x ≤ x 1 ∑ 0 ≤ y ≤ y 1 ( C x + y 1 − y x ) 2 f ( y , x 1 − x , x 2 − x 1 ) = C x 1 + y 1 x 1 C x 2 + y 1 x 2 \sum_{0\le x\le x_1}\sum_{0\le y\le y_1}(C_{x+y_1-y}^{x})^2f(y,x_1-x,x_2-x_1)=C_{x_1+y_1}^{x_1}C_{x_2+y_1}^{x_2} 0xx10yy1(Cx+y1yx)2f(y,x1x,x2x1)=Cx1+y1x1Cx2+y1x2

那么这道题中,我们需要计算

∑ 0 ≤ x ≤ x 1 ∑ 0 ≤ y ≤ y 1 C x + y 1 − y x C x + y 2 − y x f ( y , x 1 − x , x 2 − x 1 ) \sum_{0\le x\le x_1}\sum_{0\le y\le y_1}C_{x+y_1-y}^{x}C_{x+y_2-y}^{x}f(y,x_1-x,x_2-x_1) 0xx10yy1Cx+y1yxCx+y2yxf(y,x1x,x2x1)

两个式子的形式挺相近的。但是我化简不动了。不过讲道理肯定是正确的式子。

《飞鸟集》

考虑两条相交的路径。如果不考虑对应关系,它更像一个乱糟糟的毛线团——前面有两个端头,后面也有两个端头,中间搅在一块。

当然,我们可以先把毛线团的结构确定,然后再把颜色染上去。所以我们可以 交换对应关系。不难发现相交的路径数量就是 ( x 1 + y 2 y 2 ) ( x 2 + y 1 y 1 ) {x_1+y_2\choose y_2}{x_2+y_1\choose y_1} (y2x1+y2)(y1x2+y1)

代码

#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
typedef long long int_;
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
inline void writeint(int x){
	if(x > 9) writeint(x/10);
	putchar((x%10)^48);
}
inline int qkpow(int_ b,int q,int m){
	int ans = 1;
	for(; q; q>>=1,b=b*b%m)
		if(q&1) ans = ans*b%m;
	return ans;
}

const int MaxN = 200005;
const int Mod = 1e9+7;
int jc[MaxN], inv[MaxN];
void prepare(){
	jc[1] = inv[1] = 1;
	for(int i=2; i<MaxN; ++i){
		jc[i] = 1ll*jc[i-1]*i%Mod;
		inv[i] = (0ll+Mod-Mod/i)*inv[Mod%i]%Mod;
	}
	for(int i=2; i<MaxN; ++i)
		inv[i] = 1ll*inv[i]*inv[i-1]%Mod;
	jc[0] = inv[0] = 1;
}
int_ C(int n,int m){
	if(n < m) return 0; // 拿不出来
	return 1ll*jc[n]*inv[m]%Mod*inv[n-m]%Mod;
}

int main(){
	prepare();
	for(int T=readint(); T; --T){
		int x1 = readint(), x2 = readint();
		int y1 = readint(), y2 = readint();
		int_ all = C(x1+y1,y1)*C(x2+y2,y2)%Mod;
		int_ bad = C(x1+y2,y2)*C(x2+y1,y1)%Mod;
		all = (all+Mod-bad)%Mod;
		printf("%lld\n",all);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值