JZOJ5612. 【NOI2018模拟3.29】第3题

题意:

数据范围:

Analysis:

20分很显然的设 f i , j f_{i,j} fi,jDP。
50分,观察这个三个式子。类似于每次走(x+1,y),(x,y+1),根据一个步数可以确定另一个,然后组合数算,是否能够类似的做。假设我们每个走了 x , y , z x,y,z x,y,z次。就有方程:
x + y + 2 z = n x+y+2z=n x+y+2z=n x − y = m x-y=m xy=m
解得: x = y + m , z = n − m 2 − y x=y+m,z=\frac{n-m}{2}-y x=y+m,z=2nmy
也就是说对于一个确定的 y y y,其它也随之确定。显然可以用组合数算。
设: A = n − m 2 , B = n + m 2 A=\frac{n-m}{2},B=\frac{n+m}{2} A=2nm,B=2n+m
有: ∑ i = 0 A C i + B i C B i + m \sum_{i=0}^{A}C_{i+B}^{i}C_{B}^{i+m} i=0ACi+BiCBi+m
100分:快速计算组合数,又有模数。套路的用 L u c a s Lucas Lucas定理,在 m o mo mo进制下DP。因为有 i + m i+m i+m,要多设一维 0 / 1 0/1 0/1表示是否进位。
但还有一种更简单的做法:发现第三种走法等于走一次第一种,走一次第二种。
不妨假设只有第一,二种,合并出第三种。枚举多少个第一二种配对第三种,并且其可以变成第三种也可以不变成第三种,则有式子:
∑ i = 0 A 2 i C A i C B i \sum_{i=0}^{A}2^iC_{A}^iC_{B}^i i=0A2iCAiCBi
这个直接逐位枚举 m o mo mo进制下每一位的数算就好了。

Code:

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
const int N = 2e5 + 5;
const int mo = 100003;
typedef long long ll;
int inv[N],fac[N],fac_[N];
ll n,m;
inline int pow(int x,int p)
{
	int ret = 1;
	for (; p ; p >>= 1,x = (ll)x * x % mo)
	if (p & 1) ret = (ll)ret * x % mo;
	return ret;
}
inline int C(ll n,ll m)
{
	if (n < m) return 0;
	if (n >= mo) return (ll)C(n / mo,m / mo) * C(n % mo,m % mo) % mo;
	return (ll)fac[n] * fac_[m] % mo * fac_[n - m] % mo;
}
int main()
{
	freopen("move.in","r",stdin);
	freopen("move.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	if (n < m || (n + m) % 2) { puts("0"); return 0; }
	if (n == m) { puts("1"); return 0; }
	ll A = (n - m) / 2,B = (n + m) / 2; fac[0] = fac_[0] = inv[1] = 1;
	for (int i = 1 ; i < mo ; ++i)
	{
		if (i > 1) inv[i] = (ll)(mo - mo / i) * inv[mo % i] % mo;
		fac[i] = (ll)fac[i - 1] * i % mo;
		fac_[i] = (ll)fac_[i - 1] * inv[i] % mo;
	}
	int ans = 1;
	while (A > 0)
	{
		int l = A % mo,r = B % mo,now = 0;
		A /= mo,B /= mo;
		for (int i = 0 ; i <= min(l,r) ; ++i) now = (now + (ll)C(l,i) * C(r,i) % mo * pow(2,i) % mo) % mo;
		ans = (ll)ans * now % mo;
	}
	printf("%d\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值