计蒜之道2017复赛:商汤智能机器人(组合数学)

传送门

题解:
日常划水。。

枚举一下步数,其实是要求 t = 0 b ( a + t b ) ( b t ) \sum_{t=0}^b \binom{a+t}{b}\binom{b}{t}

不妨记其为 S ( a , b ) S(a,b) ,发现模数很小,于是可以根据lucas定理递归到 S ( a p , b p ) S(\frac{a}{p},\frac{b}{p}) S ( a p + 1 , b p ) S(\frac{a}{p}+1,\frac{b}{p}) (需要分类讨论)。注意到递归层数只有 O ( log p x ) O(\log_p x) 层,于是时间复杂度为 O ( 2 log p n p log p n ) O(2^{\log_p n} p \log_p n)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int p=1e5+3;
inline int add(int x,int y) {return (x+y>=p) ? (x+y-p) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+p) : (x-y);}
inline int mul(int x,int y) {return (long long)x*y%p;}
struct binom {
	int fac[p],ifac[p];
	binom() {
		fac[0]=1;
		for(int i=1;i<p;i++) fac[i]=mul(fac[i-1],i);
		ifac[0]=ifac[1]=1;
		for(int i=2;i<p;i++) ifac[i]=mul(p-p/i,ifac[p%i]);
		for(int i=2;i<p;i++) ifac[i]=mul(ifac[i-1],ifac[i]);
	}
	inline int C(int a,int b) {
		return (a<b) ? 0 : mul(fac[a],mul(ifac[b],ifac[a-b]));
	}
} C;
inline int lucas(LL a,LL b) {
	if(a<p && b<p) return C.C(a,b);
	else return mul(C.C(a%p,b%p),lucas(a/p,b/p));
}
inline int S(LL a,LL b) {
	int ans=0;
	if(b<p) {
		for(LL t=0;t<=b;t++) ans=add(ans,mul(lucas(a+t,b),lucas(b,t)));
	} else {
		LL z=(b+1)/p*p;
		for(LL t=z;t<=b;t++) ans=add(ans,mul(lucas(a+t,b),lucas(b,t)));
		int d=p-a%p; z/=p;
		int sum=0;
		for(LL t=0;t<d;++t) sum=add(sum,mul(C.C((a+t)%p,b%p),C.C(b%p,t)));
		ans=add(ans,mul(sum,dec(S(a/p,b/p),((b+1)%p?lucas(a/p+b/p,b/p):0))));
		if(d^p) {
			sum=0;
			for(LL t=d;t<p;++t) sum=add(sum,mul(C.C((a+t)%p,b%p),C.C(b%p,t)));
			ans=add(ans,mul(sum,dec(S(a/p+1,b/p),((b+1)%p?lucas(a/p+1+b/p,b/p):0))));
		}
	} return ans;
}
int main() {
	LL x,y; cin>>x>>y;
	if((x+y)&1 || x<y) puts("0");
	else cout<<S((x+y)/2,(x-y)/2)<<'\n';
}
发布了553 篇原创文章 · 获赞 227 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/83833122